android原生的數據庫實現[ContentProvider+SQLiteOpenHelpe...

   先吐槽下:最近幾周壓力老大了,前面咱們三個ios開發人員花了一個多月開發的應用要移植到android上,因爲應用相對比較複雜,有拖拽排序、離線下載、二維碼掃描,而此次,另外一個ios開發人員離職,剩下的另外一個還沒作個android,得由我帶,因而,我估計了下開發時間,大約34天,我將計劃發給領導,領導卻說最多給我15天,我半天沒說一個字:*&%¥#%**&⋯⋯&& java

   哎,出來混的,無論怎樣,儘可能吧。 android

   這個開發,咱們四張表要操做,相對於通常的移動應用,仍是比較大的,故數據庫實現確定是整個開發的第一個和相當重要的一步,因而,我整理了下面這個demo。 ios

   其實網上有不少比較不錯的orm移動開發框架,相對仍是比較優秀,能夠節省大把的開發時間,但我我的認爲,如今這個還不是很穩定,並且,在效率上,我持保守態度,移動開發上,應相對的少用反射和抽象接口,而網絡上的一些第三方的框架,卻抓住這個大用特用,我的以爲,不大好,另外,採用android原生的數據庫實現方案,還有個極大的好處是:很容易實現產品生態系統,這個是其餘的orm所不易達到的。也即,能夠垂手可得地實現咱們的幾個應用間的數據共享和交互,URI訪問便可,從而造成一個生態圈的目的,具體的,就很少說了。 sql

   這個demo是一個完整的db操做,但只給出了一個實體的db實現,不過,足以: shell

程序結構圖: 數據庫

後面的全部db操做,都會被封裝到DBManager中,也即,之後應用的db操做,只需經過DBManager進行交互接口,具體的看TestDBAct中實現: json

一、抽象實體基類 BasicEntity.java: 網絡

package blockcheng.android.model;

import java.io.Serializable;

import org.json.JSONObject;

import android.content.ContentValues;
import android.database.Cursor;
import android.os.Parcelable;
import android.provider.BaseColumns;

public abstract class BasicEntity implements BaseColumns,Serializable, Parcelable{
	private static final long serialVersionUID = 7169909425485915669L;
	
	protected String entityName;
	protected String entityId;
	protected long lastUpdateTime;
	
	public static final String sDEFAULTSORT = "  lastUpdateTime desc";
	public static final String sKEY_LASTUPDATETIMEADID = "lastUpdateTime";
	/**
	 * demo methods
	 * @param obj
	 * @return
	 */
	public static BasicEntity translateJson2Object(JSONObject obj){
		//TODO:this method must be override by subclass.
		return null;
	}

	public String getEntityName() {
		return entityName;
	}

	public void setEntityName(String entityName) {
		this.entityName = entityName;
	}

	public String getEntityId() {
		return entityId;
	}

	public void setEntityId(String entityId) {
		this.entityId = entityId;
	}

	public long getLastUpdateTime() {
		return lastUpdateTime;
	}

	public void setLastUpdateTime(long lastUpdateTime) {
		this.lastUpdateTime = lastUpdateTime;
	}
	
	
	public abstract ContentValues getContentValues();
	
	/**
	 * demo method :should be copy by subclass
	 * @param c
	 * @return
	 */
	public static BasicEntity fromCursor(Cursor c) {
		return null;
	}

	@Override
	public String toString() {
		return "id=" + entityId  + ", name="
				+ entityName + ", lastUpdateTime=" + lastUpdateTime + "";
	}
}

二、廣告實體類AdvertisementEntity.java: app

package blockcheng.android.model;

import java.io.Serializable;

import org.json.JSONObject;

import android.content.ContentValues;
import android.database.Cursor;
import android.os.Parcel;

public class AdvertisementEntity extends BasicEntity implements Serializable{
	private static final long serialVersionUID = 3045767248752772598L;
	
	/**
	 * 廣告圖片路徑
	 **/
	private String adPic;
	/**
	 * 廣告類型  1主題 2 單個商品(後可擴充,客戶端可根據廣告類型設定廣告的點擊狀態)
	 **/
	private int adType;
	/**
	 * 廣告對象地址(主題ID、單個商品ID或者其餘)
	 **/
	private String adTarget;

	//'廣告位置:1.banner(後擴充位置)
	private int adPosition;
	private String data;

	/**
	 * demo methods
	 * @param obj
	 * @return
	 */
	public static AdvertisementEntity translateJson2Object(JSONObject obj){
		//TODO:implement it later.
		AdvertisementEntity aEntity = new AdvertisementEntity();
		return aEntity;
	}
	public String getAdPic() {
		return adPic;
	}

	public void setAdPic(String adPic) {
		this.adPic = adPic;
	}

	public int getAdType() {
		return adType;
	}

	public void setAdType(int adType) {
		this.adType = adType;
	}

	public String getAdTarget() {
		return adTarget;
	}

	public void setAdTarget(String adTarget) {
		this.adTarget = adTarget;
	}

	public int getAdPosition() {
		return adPosition;
	}

	public void setAdPosition(int adPosition) {
		this.adPosition = adPosition;
	}

	public String getData() {
		return data;
	}

	public void setData(String data) {
		this.data = data;
	}

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

	/******************************************************************/
	/*********************Database config information********************/
	/******************************************************************/
	
	public static final String sTABLE_NAME = "AdvertisementEntity";
	public static final String sKEY_ADID = "adId";
	public static final String sKEY_ADNAME = "adName";
	
	public static final String sKEY_ADTYPE = "adType";
	public static final String sKEY_ADPIC = "adPic";
	public static final String sKEY_ADTARGET = "adTarget";
	
	/*
	 * 要查詢的所有字段
	 */
	public  static String[] ADS_PROJECTION_ALL = new String[] {
		"adId","adName","lastUpdateTime",
		"adType","adPic","adTarget",
	};

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		// TODO Auto-generated method stub
	}

	@Override
	public ContentValues getContentValues() {
		// TODO Auto-generated method stub
		final ContentValues values = new ContentValues();
		values.put(sKEY_ADID, getEntityId());
		values.put(sKEY_ADNAME, getEntityName());
		values.put(sKEY_ADTYPE, adType);
		
		values.put(sKEY_ADPIC, adPic);
		values.put(sKEY_ADTARGET, adTarget);
		return values;
	}

	public static AdvertisementEntity fromCursor(Cursor c) {
		AdvertisementEntity aEntity = new AdvertisementEntity();
		
		aEntity.entityId = c.getString(c.getColumnIndexOrThrow(sKEY_ADID));
		aEntity.entityName = c.getString(c.getColumnIndexOrThrow(sKEY_ADNAME));
		aEntity.adPic = c.getString(c.getColumnIndexOrThrow(sKEY_ADTARGET));
		aEntity.adType = c.getInt(c.getColumnIndexOrThrow(sKEY_ADTYPE));
		aEntity.lastUpdateTime = c.getLong(c.getColumnIndexOrThrow(BasicEntity.sKEY_LASTUPDATETIMEADID));
		return aEntity;
	}

	@Override
	public String toString() {
		return "AdvertisementEntity [" + super.toString()+ "adPic= "+ adPic + ", adType=" + adType
				+ ", adTarget=" + adTarget + ", adPosition=" + adPosition
				+ ", data=" + data + "]" + super.toString();
	}
}
三、DB的一些常量配置 DBConfig.java:

package blockcheng.android.service.database;

import android.net.Uri;

public interface DBConfig {
	public static final String DATABASE_NAME = "blockchengDB";
	public static final int DATABASE_VERSION = 1;
	public static final String DB_TAG = "blockcheng";
	
	public static final String AUTHORITY = "blockcheng.android";
	// content url
	public static final Uri CONTENT_URI_AdvertisementEntity = Uri
			.parse("content://" +AUTHORITY+
					"/AdvertisementEntity");
	//search value
	public static final int sSEARCH = 10;
	public static final int sADVERTISEMENT  = 100;
	public static final int sADVERTISEMENT_ID  = 101;

}
四、建表類DBHelper.java:

package blockcheng.android.service.database;

import blockcheng.android.model.AdvertisementEntity;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DBHelper extends SQLiteOpenHelper implements DBConfig{
	public DBHelper(Context context) {
		super(context, DBConfig.DATABASE_NAME, null, DBConfig.DATABASE_VERSION);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		// TODO Auto-generated method stub
		StringBuffer createAdSql = new StringBuffer("CREATE TABLE'");
		createAdSql.append(AdvertisementEntity.sTABLE_NAME);
		createAdSql.append( "'('adId'  TEXT NOT NULL," );
		createAdSql.append( "'adName'  TEXT,");
		createAdSql.append("'lastUpdateTime'  real DEFAULT 0,");
		createAdSql.append("'adType'  INTEGER,");
		
		createAdSql.append("'adPic'  TEXT,");
		createAdSql.append( "'adTarget'  TEXT,");
		createAdSql.append( "PRIMARY KEY ('adId')" );
		createAdSql.append( ");");;
		
		Log.i(DBConfig.DB_TAG, "createAdSql::"+createAdSql.toString());
		db.execSQL(createAdSql.toString());
		
		String createIndexSql_0 = "CREATE INDEX 'id' ON '" +
				AdvertisementEntity.sTABLE_NAME +
				"' ('adId' ASC);";
		db.execSQL(createIndexSql_0);

	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// TODO Auto-generated method stub
		Log.w(DBConfig.DB_TAG, "Upgrading database from version " + oldVersion
				+ " to " + newVersion + ", which will destroy all old data");

		db.execSQL("DROP TABLE IF EXISTS " +
				AdvertisementEntity.sTABLE_NAME);
		onCreate(db);
	}

}
五、contentProvider實現類DemoContentProvider.java:

package blockcheng.android.service.database;

import java.util.HashMap;

import blockcheng.android.model.AdvertisementEntity;
import blockcheng.android.model.BasicEntity;

import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class DemoContentProvider extends ContentProvider {
	private SQLiteOpenHelper dbHelper;
	private static final UriMatcher URI_MATCHER;
	static {//TODO 須要整合下面的地址:
		URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
		URI_MATCHER.addURI(DBConfig.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
				DBConfig.sSEARCH);
		URI_MATCHER.addURI(DBConfig.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY
				+ "/*", DBConfig.sSEARCH);
		
		//advertisement uri config
		URI_MATCHER.addURI(DBConfig.AUTHORITY, AdvertisementEntity.sTABLE_NAME, DBConfig.sADVERTISEMENT);
		URI_MATCHER.addURI(DBConfig.AUTHORITY, AdvertisementEntity.sTABLE_NAME+"/*", DBConfig.sADVERTISEMENT_ID);
		
	}

	// TODO: need more investigate.
	private static final HashMap<String, String> SUGGESTION_PROJECTION_MAP;
	static {
		SUGGESTION_PROJECTION_MAP = new HashMap<String, String>();
		SUGGESTION_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_1,
				"topicName " + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_1);
		SUGGESTION_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_2,
				"goodName " + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_2);
		SUGGESTION_PROJECTION_MAP.put(
				SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, AdvertisementEntity._ID + " AS "
						+ SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
		SUGGESTION_PROJECTION_MAP.put(AdvertisementEntity._ID, AdvertisementEntity._ID);
	}

	@Override
	public boolean onCreate() {
		// TODO Auto-generated method stub
		dbHelper = new DBHelper(getContext());
		return true;
	}

	// TODO: update the manifest accordingly.
	public String getType(Uri uri) {
		switch (URI_MATCHER.match(uri)) {
		case DBConfig.sADVERTISEMENT:
		case DBConfig.sADVERTISEMENT_ID:
			return "vnd.android.cursor.dir/" + DBConfig.AUTHORITY + "."
					+ AdvertisementEntity.sTABLE_NAME;
		
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues initialValues) {
		// TODO Auto-generated method stub
		Log.i(DBConfig.DB_TAG, "insert::"+uri.toString());
		ContentValues values;

		SQLiteDatabase db = dbHelper.getWritableDatabase();
		switch(URI_MATCHER.match(uri)){
		case DBConfig.sADVERTISEMENT:
			if (initialValues != null) {
				values = new ContentValues(initialValues);
				values.put(BasicEntity.sKEY_LASTUPDATETIMEADID, System.currentTimeMillis());
			} else {
				values = new ContentValues();
			}
			final long rowId = db.insert(AdvertisementEntity.sTABLE_NAME, AdvertisementEntity.sKEY_ADPIC, values);
			if (rowId > 0) {
				Uri insertUri = ContentUris.withAppendedId(DBConfig.CONTENT_URI_AdvertisementEntity, rowId);
				getContext().getContentResolver().notifyChange(uri, null);
				return insertUri;
			}
			throw new SQLException("Failed to insert row into " + uri);
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
			
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// TODO Auto-generated method stub
		Log.i(DBConfig.DB_TAG, "delete::"+uri.toString());
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		int count;
		switch (URI_MATCHER.match(uri)) {
		case DBConfig.sADVERTISEMENT:
			count = db.delete(AdvertisementEntity.sTABLE_NAME, selection, selectionArgs);
			break;
		case DBConfig.sADVERTISEMENT_ID:
			String adId = uri.getPathSegments().get(1);
			count = db.delete(AdvertisementEntity.sTABLE_NAME,
					AdvertisementEntity.sKEY_ADID
							+ "="
							+ adId
							+ (!TextUtils.isEmpty(selection) ? " AND ("
									+ selection + ')' : ""), selectionArgs);
			break;
		default:
			throw new IllegalArgumentException("   Unknown URI " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
	

	@Override
	public int update(Uri uri, ContentValues values, String where,
			String[] whereArgs) {
		Log.i(DBConfig.DB_TAG, "update::"+uri.toString() +": value="+values.toString());
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		int count = -1;
		switch (URI_MATCHER.match(uri)) {
		case DBConfig.sADVERTISEMENT_ID:
			Log.i(DBConfig.DB_TAG, "update::sADVERTISEMENT_ID");
			String adverstisementId = uri.getPathSegments().get(1);
			count = db.update(
					AdvertisementEntity.sTABLE_NAME,
					values,
					AdvertisementEntity.sKEY_ADID
							+ "='"
							+ adverstisementId
							+ "'"
							+ (!TextUtils.isEmpty(where) ? " AND (" + where
									+ ')' : ""), whereArgs);
			break;
		case DBConfig.sADVERTISEMENT:
			Log.i(DBConfig.DB_TAG, "update::sADVERTISEMENT");
			String aidString = values.getAsString(AdvertisementEntity.sKEY_ADID);
			values.remove(AdvertisementEntity.sKEY_ADID);
			count = db.update(
					AdvertisementEntity.sTABLE_NAME,
					values,
					AdvertisementEntity.sKEY_ADID
					+ "='"
					+ aidString
					+ "'"
					+ (!TextUtils.isEmpty(where) ? " AND (" + where
							+ ')' : ""), whereArgs);
			break;
		
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		return count;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		Log.i(DBConfig.DB_TAG, "query::"+uri.toString());
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		String orderBy;
		switch (URI_MATCHER.match(uri)) {
		case DBConfig.sADVERTISEMENT:
			qb.setTables(AdvertisementEntity.sTABLE_NAME);
			break;
		case DBConfig.sADVERTISEMENT_ID:
			qb.setTables(AdvertisementEntity.sTABLE_NAME);
			qb.appendWhere(AdvertisementEntity.sKEY_ADID + "='"
					+ uri.getPathSegments().get(1) +"'");
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		// If no sort order is specified use the default
		if (TextUtils.isEmpty(sortOrder)) {
			orderBy = BasicEntity.sDEFAULTSORT;
		} else {
			orderBy = sortOrder;
		}
		
		SQLiteDatabase db = dbHelper.getReadableDatabase();
		Cursor c = qb.query(db, projection, selection, selectionArgs, null,
				null, orderBy);
		c.setNotificationUri(getContext().getContentResolver(), uri);

		return c;
	}

	

}
測試界面佈局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="15dip" >

    <EditText
        android:id="@+id/et_condition"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:text="1"
         >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/db_button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:onClick="handleEvent"
        android:text="add " />

    <Button
        android:id="@+id/db_button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:onClick="handleEvent"
        android:text="delete" />

    <Button
        android:id="@+id/db_button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:onClick="handleEvent"
        android:text="update" />

    <Button
        android:id="@+id/db_button4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:onClick="handleEvent"
        android:text="query" />

</LinearLayout>
測試類TestDBAct.java:

package cn.helloclq.android.activity;

import blockcheng.android.R;
import blockcheng.android.model.AdvertisementEntity;
import blockcheng.android.service.database.DBManager;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

public class TestDBAct extends Activity {

	EditText etCondition;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.dbtest_activity);
		etCondition = (EditText)findViewById(R.id.et_condition);
		
	}
	
	
	public void handleEvent(View view){

		String adIdString = etCondition.getText().toString();
		AdvertisementEntity aEntity = new AdvertisementEntity();
		aEntity.setEntityId(adIdString);
		aEntity.setEntityName("ad"+adIdString);
		aEntity.setAdType(Integer.parseInt(adIdString));
		aEntity.setAdTarget(adIdString);
		
		
		//public WebTaskTest(Context context, boolean showDialog,
//		boolean cancelAble, String dialogLoadingStr,
//		WebRequestCallbackInfc cb)
		switch(view.getId()) {
		case R.id.db_button1://add 
			DBManager.getInstance().addAdvertiseMent(getContentResolver(), aEntity);
			break;
		case R.id.db_button2://delete
			DBManager.getInstance().deleteAdvertiseMentById(getContentResolver(), adIdString);
			
			break;
		case R.id.db_button3://update
			aEntity.setEntityName("ad update"+adIdString);
			DBManager.getInstance().updateAdervertiseEntity(getContentResolver(), aEntity);
			break;
		case R.id.db_button4://query
			DBManager.getInstance().querAllAdvertisementEntity(getContentResolver());
			break;
		
		}
		
		
		
	}
	
	
}
運行效果圖:


運行日誌: 框架

08-07 10:52:50.305: I/blockcheng(458): query::content://blockcheng.android/AdvertisementEntity/1
08-07 10:52:50.415: I/blockcheng(458): createAdSql::CREATE TABLE'AdvertisementEntity'('adId'  TEXT NOT NULL,'adName'  TEXT,'lastUpdateTime'  real DEFAULT 0,'adType'  INTEGER,'adPic'  TEXT,'adTarget'  TEXT,PRIMARY KEY ('adId'));
08-07 10:52:50.434: I/blockcheng(458): insert::content://blockcheng.android/AdvertisementEntity
08-07 10:52:50.455: I/blockcheng(458): addAdvertiseMent::AdvertisementEntity [id=1, name=ad1, lastUpdateTime=0adPic= null, adType=1, adTarget=1, adPosition=0, data=null]id=1, name=ad1, lastUpdateTime=0
08-07 10:53:08.567: I/blockcheng(458): query::content://blockcheng.android/AdvertisementEntity
08-07 10:53:08.575: I/blockcheng(458): ad:AdvertisementEntity [id=1, name=ad1, lastUpdateTime=1375843970443adPic= 1, adType=1, adTarget=null, adPosition=0, data=null]id=1, name=ad1, lastUpdateTime=1375843970443
08-07 10:53:15.585: I/blockcheng(458): update::content://blockcheng.android/AdvertisementEntity: value=adTarget=1 adType=1 adPic=null adId=1 lastUpdateTime=1375843995585 adName=ad update1
08-07 10:53:15.585: I/blockcheng(458): update::sADVERTISEMENT
08-07 10:53:17.355: I/blockcheng(458): delete::content://blockcheng.android/AdvertisementEntity/1
08-07 10:53:18.835: I/blockcheng(458): query::content://blockcheng.android/AdvertisementEntity

麻雀雖小,五臟俱全,加多張表的話,也是如此的,就這樣吧,都寫了好一下子了。

補充manifest文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="blockcheng.android"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="4"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>  
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
	<uses-permission android:name="android.permission.READ_LOGS"></uses-permission>
    <application
        android:allowBackup="true"
        android:label="@string/app_name"
         >
         <activity
            android:name="cn.helloclq.android.activity.TestAct"
            android:label="@string/app_name"
            android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation"
            android:screenOrientation="portrait" >
        </activity>
         <activity
            android:name="cn.helloclq.android.activity.TestDBAct"
            android:label="@string/app_name"
            android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider
			android:exported="false"
            android:authorities="blockcheng.android"
            android:name="blockcheng.android.service.database.DemoContentProvider" />
        
    </application>

</manifest>
相關文章
相關標籤/搜索