Android-ContentProvider數據庫操做

在實際的開發過程當中,Android提供了5種方式存儲數據:    java

1.文件存儲數據    
2.使用 Sharedpreferences 存儲數據    
3.SQLite數據庫存儲數據    
4.使用ContentProvider存儲數據    
5.網絡存儲數據
android

首先咱們先簡單瞭解下文件、SharedPreferred如何進行數據存儲 sql

1.文件存儲操做 shell

    文件存儲通常存儲在sdcard或者ROM,當文件存儲在ROM上時,若是是存儲在除本身私有空間外(data/data/包名/),在其餘地方是須要system系統權限的(http://my.oschina.net/zhoulc/blog/119282)。

    文件IO流建立比較簡單,就不詳述了,在進行文件存儲的時候注意兩個路徑方法就行。
    存儲到ROM
        Context mContext = XXXActivity.this;

        mContext.getFilesDir().getAbsolutePath();
        獲取路徑:/data/data/包名/files
    存儲到sdCard :
        首先判斷sdcard是否可用

         Environment.getExternalStorageState()是否等於Environment.MEDIA_MOUNTED
         Environment.getExternalStorageDirectory().getAbsolutePath()
         對sdcard目錄操做須要添加權限:
         <!-- 添加對SDCARD的寫權限 -->   
         < uses-permission   android:name          ="android.permission.WRITE_EXTERNAL_STORAGE" >
         獲取路徑:/sdcard
    拓展下 :支持u盤的移動設備,u盤通常都是掛載mnt/sda/sdal外設上面
    順帶說下之前一直糾結的一個問題:
        getApplicationContext() 生命週期是整個應用,應用摧毀它才摧毀
        Activity.this的context屬於activity ,activity 摧毀他就摧毀
數據庫

2.經過Sharedpreferences進行數據存儲
網絡

private final static String PERFS_NAME = "com.zlc.test"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //存放 //第一個參數是存儲時的名稱,第二個參數則是文件的打開方式(Context. MODE_PRIVATE) SharedPreferences userInfo = getSharedPreferences(PERFS_NAME,0); SharedPreferences.Editor editor = userInfo.edit(); editor.putString("userName", "zhoulc"); editor.putString("passWord", "ds"); editor.commit(); //讀取 System.out.println("##########################################"); SharedPreferences readInfo = getSharedPreferences(PERFS_NAME, 0); String name = readInfo.getString("userName", "no_name"); String psword = readInfo.getString("passWord", "000000"); System.out.println("name = "+name+" password = "+psword); }
使用過程當中注意三個問題

    1)getSharedPreferences有兩個參數,第一個參數是存儲時的名稱, 第二個參數則是文件的打開方式(通常使用0或者Context.MODE_PRIVATE)
    2)默認的模式爲0或MODE_PRIVATE,若是訪問其餘應用中的Preference,前提條件是:該 preference建立時指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE權限。
    3)千萬不要偷懶寫成
        userInfo.edit().putString("userName", "zhoulc");
        userInfo.edit().putString("passWord", "ds");
        userInfo.edit().commit();
        edit()方法每次都要產生一個新的SharedPreferences.Edit類的對象,因此commit
以後數據沒有存儲成功。


3.其餘幾個就不詳細介紹了,說下今天的重點ContentProvider app

    建立一個可對數據庫進行操做的ContentProvider咱們先要了解涉及到的知識點:
    (1)Parcelable(實體類數據通常會用在進程之間通訊)
           http://my.oschina.net/zhoulc/blog/172163
    (2)BaseColumns,這個類只是提供了兩個字段,一個是"_id"一個是"_count",便於調用數據庫時致使拼寫錯誤,你也能夠擴展它,或者自定義這麼個,而後直接調用它的常量名,防止寫sql語句時把列名拼錯。
ide

package android.provider; public interface BaseColumns { /** * The unique ID for a row. * <P>Type: INTEGER (long)</P> */ public static final String _ID = "_id"; /** * The count of rows in a directory. * <P>Type: INTEGER</P> */ public static final String _COUNT = "_count"; }
    (3)SQLiteOpenHelper,包裝了數據庫的建立、打開、更新的抽象類,經過實現和使用SQLiteOpenHandle能夠隱去數據庫打開的以前判斷數據庫是否須要建立或更新的邏輯。
            主要實現三個方法
            建立數據庫:public DatabaseHelper(Context context)
             建立表:public void onCreate(SQLiteDatabase db)
            更新表:public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
     (4)UriMatcher用來匹配URI。
            主要實現兩個接口:
             添加須要匹配的URI:MATCHER.addURI(String authority, String path, int code) 進行匹配返回定義的value;MATCHER.match(Uri uri)
            例:
                MATCHER.addURI(Information.AUTHORITY, "informations", INFORMATIONS);
                MATCHER.addURI(Information.AUTHORITY, "informations/#", INFORMATION);
                # 號爲通配符
                * 號爲任意字符
    (5)ContentUris一個工具類,主要是用來處理使用 "content" 約束的Uri對象,常常用到條件查詢某個_ID的數據。
            主要實現兩個接口:
            static long parseId(Uri contentUri)  將uri中的id解析出來,此方法返回的是一個long型的id。
            static Uri withAppendedId(Uri contentUri, long id)在指定的uri後面添加一條id
爲指定參數的記錄。 
    (6)SQLiteDatabase,這個類是核心類,用於管理和操做SQLite數據庫,幾乎全部的數據庫操做,最終都將由這個類完成。
    (7)ContentProvider,提供數據庫增刪改查的接口。
            主要實現接口:
            public int delete(Uri uri, String selection, String[] selectionArgs)
            public String getType(Uri uri)
            public Uri insert(Uri uri, ContentValues values)
            public boolean onCreate()
            public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder)
            public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
    (8)ContentResolver接口和ContentProvider相似,兩個區別一個是用戶是經過ContentResolver調用ContentProvider提供的接口。
    以上類都只是簡單介紹,有興趣的朋友能夠去研究下源碼和實現過程。這裏主要講使用過程和一些注意細節。


4.ContentProvider 在使用過程當中須要注意兩點

    (1)在AndroidManifest.xml裏面須要註冊這個ContentProvider     
            <provider android:name=".MyProvider" android:authorities="com.zlc.provider.MyProvider" />
    (2)當提供給其餘進程調用(假如是其餘應用),若是當前提供ContentProvider的應用在退出的時候把本身給kill掉了(這個時候ContentProvider也沒法使用),則咱們須要在AndroidManifest.xml裏面再添加一條屬性
            android:process="com.zlc.provider.MyProvider"
            爲該組件指定一個不一樣的默認進程


5.下面貼一下具體實現代碼 工具

     (1)ContentProvider提供者TestContentProvider.apk
            實體類:Information.java
package com.zlc.provider;

import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.BaseColumns;

public class Information implements Parcelable,BaseColumns{
	public final static String AUTHORITY = "com.zlc.provider.MyProvider";
	public final static Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/informations");
	//表字段
	public final static String INFO_ID = "info_id";
	public final static String INFO_NAME = "info_name";
	public final static String INFO_AGE = "info_age";
	
	private String info_id,info_name,info_age;

	public Information(Parcel source){
		info_id = source.readString();
		info_name = source.readString();
		info_age = source.readString();
	}
	public String getInfo_id() {
		return info_id;
	}

	public void setInfo_id(String info_id) {
		this.info_id = info_id;
	}

	public String getInfo_name() {
		return info_name;
	}

	public void setInfo_name(String info_name) {
		this.info_name = info_name;
	}

	public String getInfo_age() {
		return info_age;
	}

	public void setInfo_age(String info_age) {
		this.info_age = info_age;
	}

	@Override
	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		// TODO Auto-generated method stub
		dest.writeString(info_id);
		dest.writeString(info_name);
		dest.writeString(info_age);
	}
	public final static Parcelable.Creator<Information> CREATOR = new Parcelable.Creator<Information>() {

		@Override
		public Information createFromParcel(Parcel source) {
			// TODO Auto-generated method stub
			return new Information(source);
		}

		@Override
		public Information[] newArray(int size) {
			// TODO Auto-generated method stub
			return new Information[size];
		}
	};
}
            MyProvider.java
package com.zlc.provider;

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.provider.BaseColumns;
import android.util.Log;

public class MyProvider extends ContentProvider {
	private SQLiteDatabase sqDb;
	private DatabaseHelper helper;
	// 數據庫名
	private final static String DATABASE_NAME = "zhoulc.db";
	// 版本
	private static final int DATABASE_VERSION = 1;
	// 表名
	private static final String TABLE_NAME = "Information";
	// 建立表的sql語句
	private final static String CREATE_TABLE = "Create table " + TABLE_NAME
			+ "( "+Information._ID+" integer primary key autoincrement," + Information.INFO_ID
			+ " TEXT," + Information.INFO_NAME + " TEXT," + Information.INFO_AGE
			+ " TEXT);";

	// Declaration Datababsehelper
	private static class DatabaseHelper extends SQLiteOpenHelper {

		public DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			// TODO Auto-generated method stub
			db.execSQL(CREATE_TABLE);
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			// TODO Auto-generated method stub
			db.execSQL("DROP TABLE IF EXISTS" + TABLE_NAME);
			onCreate(db);
		}

	}

	// UriMatcher add URI
	private static final UriMatcher MATCHER = new UriMatcher(
			UriMatcher.NO_MATCH);
	private final static int INFORMATIONS = 1;
	private final static int INFORMATION = 2;
	static {
		MATCHER.addURI(Information.AUTHORITY, "informations", INFORMATIONS);
		MATCHER.addURI(Information.AUTHORITY, "informations/#", INFORMATION);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// TODO Auto-generated method stub
		sqDb = helper.getWritableDatabase();
		int count = 0;
		switch (MATCHER.match(uri)) {
		case INFORMATIONS:
			count = sqDb.delete(TABLE_NAME, selection, selectionArgs);
			break;
		default:
			throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
		}
		return count;
	}

	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		switch (MATCHER.match(uri)) {
		case INFORMATIONS:
			return "vnd.android.cursor.dir/Information";
		case INFORMATION:
			return "vnd.android.cursor.item/Information";
		default:
			throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		// TODO Auto-generated method stub
		sqDb = helper.getWritableDatabase();
		Uri insertUri = null;
		long rowid = 0;
		switch (MATCHER.match(uri)) {
		case INFORMATIONS:
			rowid = sqDb.insert(TABLE_NAME, Information.INFO_ID, values);
			insertUri = ContentUris.withAppendedId(uri, rowid);
			Log.i("zhoulc", "insert record...values:" + values.toString());
			break;
		default:
			throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
		}
		return insertUri;
	}

	@Override
	public boolean onCreate() {
		// TODO Auto-generated method stub
		helper = new DatabaseHelper(getContext());
		return helper == null ? false : true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		// TODO Auto-generated method stub
		sqDb = helper.getWritableDatabase();
		switch (MATCHER.match(uri)) {
		case INFORMATIONS:
			Cursor cursor = sqDb.query(TABLE_NAME, projection, selection,
					selectionArgs, null, null, sortOrder);
			return cursor;
		case INFORMATION://條件查詢,
			long id = ContentUris.parseId(uri);
			String where = Information._ID + "=" + id; 
			 if (selection != null && !"".equals(selection))  
             {  
                 where = where + " and " + selection;  
             }  
             return sqDb.query(TABLE_NAME, projection, where, selectionArgs, null,  
                 null, sortOrder);  
		default:
			throw new IllegalArgumentException("unknow uri" + uri.toString());
		}
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// TODO Auto-generated method stub
		sqDb = helper.getWritableDatabase();
		int count = 0;
		switch (MATCHER.match(uri)) {
		case INFORMATIONS:
			count = sqDb.update(TABLE_NAME, values, selection, selectionArgs);
			return count;
		default:
			throw new IllegalArgumentException("unknow uri" + uri.toString());
		}
		
	}

}

            在同一個應用自己裏面(進程)測試插入數據:MainActivity.java oop

package com.zlc.provider;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		Context mContext = MainActivity.this;
		Uri myUri = Information.CONTENT_URI;
		ContentValues values = new ContentValues();
		values.put(Information.INFO_NAME, "zhoulc");
		values.put(Information.INFO_AGE, "99");
		getContentResolver().insert(myUri, values);
		
	}
}
運行結果:
              

其餘應用裏面測試(跨進程使用)

            TestActivity.java

package com.zlc.database;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;

public class TestActivity extends Activity {
	private ContentResolver resolver;
	public final static String AUTHORITY = "com.zlc.provider.MyProvider";
	private  final static Uri CONTENT_URIS = Uri.parse("content://"+AUTHORITY+"/informations");
	private  final static Uri CONTENT_URI =  Uri.parse("content://"+AUTHORITY+"/informations/1");
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		resolver = getContentResolver();
		//step 1 insert data
		ContentValues values = new ContentValues();
		values.put("info_name", "zhoulc");
		values.put("info_age", "24");
		insert(CONTENT_URIS,values);
		//查詢
		Cursor cursor = query(CONTENT_URI,null,null,null,null);
		if(cursor != null){
			if(cursor.moveToFirst()){
				int index[] = new int[]{
					cursor.getColumnIndex("info_id"),
					cursor.getColumnIndex("info_name"),
					cursor.getColumnIndex("info_age")
				};
				do {
					System.out.println(cursor.getString(index[1]));
					System.out.println(cursor.getString(index[2]));
				} while (cursor.moveToNext());
			}
		}
	}
//	該方法用於往ContentProvider添加數據。
	public Uri insert(Uri uri,ContentValues values){
		Uri dst = resolver.insert(uri, values);
		return dst;
	}
//	該方法用於從ContentProvider刪除數據。
	public int delete(Uri uri,String where, String[] selectionArgs){
		int colums = resolver.delete(CONTENT_URI, where, selectionArgs);
		return colums;
	}
//	該方法用於更新ContentProvider中的數據。
	public int update(Uri uri,ContentValues values, String where, String[] selectionArgs){
		int colums = resolver.update(CONTENT_URI, values, where, selectionArgs);
		return colums;
	}
//	該方法用於從ContentProvider中獲取數據。
	public Cursor query(Uri uri,String[] projection, String where, String[] selectionArgs, String sortOrder){
		Cursor cursor = resolver.query(CONTENT_URI, projection, where, selectionArgs, sortOrder);
		return cursor;
	}
		
}

6.運行過程當中遇到的一些問題以及如何解決

(1)Open quote is expected for attribute "{1}" associated with an element type "
android:authorities".
  android:authorities="com.zlc.provider.MyProvider" /
解決:不能使用中文的引號
(2)E/AndroidRuntime( 4509): FATAL EXCEPTION: main
E/AndroidRuntime( 4509): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.zlc.provider/com.zlc.provider.MainActivity}: java.lang.IllegalArgumentException: Unknown URL content://com.zlc.provider.MyProviderinformations
E/AndroidRuntime( 4509):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
E/AndroidRuntime( 4509):        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
E/AndroidRuntime( 4509):        at android.app.ActivityThread.access$600(ActivityThread.java:141)
E/AndroidRuntime( 4509):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
E/AndroidRuntime( 4509):        at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 4509):        at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime( 4509):        at android.app.ActivityThread.main(ActivityThread.java:5041)
E/AndroidRuntime( 4509):        at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 4509):        at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime( 4509):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
E/AndroidRuntime( 4509):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
E/AndroidRuntime( 4509):        at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 4509): Caused by: java.lang.IllegalArgumentException: Unknown URL content://com.zlc.provider.MyProviderinformations
E/AndroidRuntime( 4509):        at android.content.ContentResolver.insert(ContentResolver.java:862)
E/AndroidRuntime( 4509):        at com.zlc.provider.MainActivity.onCreate(MainActivity.java:17)
E/AndroidRuntime( 4509):        at android.app.Activity.performCreate(Activity.java:5104)
E/AndroidRuntime( 4509):        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
E/AndroidRuntime( 4509):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
E/AndroidRuntime( 4509):        ... 11 more
W/ActivityManager( 2138):   Force finishing activity com.zlc.provider/.MainActivity
D/dalvikvm( 2138): GC_FOR_ALLOC freed 596K, 13% free 7327K/8412K, paused 63ms, total 63ms
聲明的時候掉了一個public final static Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/informations");
(3)E/AndroidRuntime( 5411): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.zlc.provider/com.zlc.provider.MainActivity}: android.database.sqlite.SQLiteException: near "tableInformation": syntax error (code 1): , while compiling: Create tableInformation(_id integer primary key autoincrement,info_idTEXT,info_nameTEXT,info_ageTEXT);
E/AndroidRuntime( 5411):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
E/AndroidRuntime( 5411):        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
E/AndroidRuntime( 5411):        at android.app.ActivityThread.access$600(ActivityThread.java:141)
E/AndroidRuntime( 5411):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
E/AndroidRuntime( 5411):        at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 5411):        at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime( 5411):        at android.app.ActivityThread.main(ActivityThread.java:5041)
E/AndroidRuntime( 5411):        at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 5411):        at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime( 5411):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
E/AndroidRuntime( 5411):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
E/AndroidRuntime( 5411):        at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 5411): Caused by: android.database.sqlite.SQLiteException: near "tableInformation": syntax error (code 1): , while compiling: Create tableInformation(_id integer primary key autoincrement,info_idTEXT,info_nameTEXT,info_ageTEXT);
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:882)
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:493)
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1663)
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1594)
E/AndroidRuntime( 5411):        at com.zlc.provider.MyProvider$DatabaseHelper.onCreate(MyProvider.java:39)
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:252)
E/AndroidRuntime( 5411):        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
E/AndroidRuntime( 5411):        at com.zlc.provider.MyProvider.insert(MyProvider.java:92)
E/AndroidRuntime( 5411):        at android.content.ContentProvider$Transport.insert(ContentProvider.java:201)
E/AndroidRuntime( 5411):        at android.content.ContentResolver.insert(ContentResolver.java:866)
E/AndroidRuntime( 5411):        at com.zlc.provider.MainActivity.onCreate(MainActivity.java:17)
E/AndroidRuntime( 5411):        at android.app.Activity.performCreate(Activity.java:5104)
E/AndroidRuntime( 5411):        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
E/AndroidRuntime( 5411):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
E/AndroidRuntime( 5411):        ... 11 more
W/ActivityManager( 2138):   Force finishing activity com.zlc.provider/.MainActivity
private final static String CREATE_TABLE = "Create table " + TABLE_NAME
+ "( _id integer primary key autoincrement," + Information.INFO_ID
+ " TEXT," + Information.INFO_NAME + " TEXT," + Information.INFO_AGE+ " TEXT);";
注意空格

代碼下載

相關文章
相關標籤/搜索