Android 库中的 SQLite 数据库,它会在应用程序之间共享吗?
SQLite Database in Android library, Will it be shared among apps?
我开发的应用程序中很少有通用功能,因此我创建了一个库来将通用代码放在一个点上。我在库中实现了 SQLite 数据库。
我的问题是图书馆的 SQLite 数据库会被应用程序共享吗?
我的意思是当从应用程序 A(使用公共库)插入 X 值时,是否也可以从应用程序 B(使用公共库)访问此数据。
我认为数据不会共享,因为每个应用程序都有自己的存储空间,数据只会保存在该存储空间中,这一点仍需澄清。
您可以将数据存储在私人应用程序文件夹之外,并从任何应用程序访问它。
如果您将数据存储在私有应用程序文件夹中,则只有在您拥有相同的 sharedUserId 时才能共享私有数据。应用程序必须使用相同的证书进行签名才能共享。
在应用程序之间共享数据的更好方法是创建一个 ContentProvider。它提供了与数据库类似的接口,并且可以通过应用程序权限提供访问限制。
您可以使用 ContentProviders
将数据从一个应用程序共享到 another.For 实例,方法是在您的应用程序中创建一个内容提供程序 class,它可以保存图像元数据项。我们将使用本地 SQLite 数据库来存储数据,但您可以使用任何您喜欢的地方来存储数据。
首先创建一个 ImagesProvider
class 扩展 ContentProvider
class 并覆盖以下方法。
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.net.Uri;
import android.util.Log;
public class ImagesProvider extends ContentProvider {
private static final String PROVIDER_NAME = "androidcontentproviderdemo.androidcontentprovider.images";
private static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/images");
private static final int IMAGES = 1;
private static final int IMAGE_ID = 2;
private static final UriMatcher uriMatcher = getUriMatcher();
private static UriMatcher getUriMatcher() {
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "images", IMAGES);
uriMatcher.addURI(PROVIDER_NAME, "images/#", IMAGE_ID);
return uriMatcher;
}
private ImageDatabase imageDataBase = null;
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case IMAGES:
return "vnd.android.cursor.dir/vnd.com.androidcontentproviderdemo.androidcontentprovider.provider.images";
case IMAGE_ID:
return "vnd.android.cursor.item/vnd.com.androidcontentproviderdemo.androidcontentprovider.provider.images";
}
return "";
}
@Override
public boolean onCreate() {
Context context = getContext();
imageDataBase = new ImageDatabase(context);
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
String id = null;
if(uriMatcher.match(uri) == IMAGE_ID) {
//Query is for one single image. Get the ID from the URI.
id = uri.getPathSegments().get(1);
}
return imageDataBase.getImages(id, projection, selection, selectionArgs, sortOrder);
}
@Override
public Uri insert(Uri uri, ContentValues values) {
try {
long id = imageDataBase.addNewImage(values);
Uri returnUri = ContentUris.withAppendedId(CONTENT_URI, id);
return returnUri;
} catch(Exception e) {
return null;
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
String id = null;
if(uriMatcher.match(uri) == IMAGE_ID) {
//Delete is for one single image. Get the ID from the URI.
id = uri.getPathSegments().get(1);
}
return imageDataBase.deleteImages(id);
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
String id = null;
if(uriMatcher.match(uri) == IMAGE_ID) {
//Update is for one single image. Get the ID from the URI.
id = uri.getPathSegments().get(1);
}
return imageDataBase.updateImages(id, values);
}
}
要存储内容,我们的内容提供商需要一个数据库助手 class。创建一个ImageDataBase
class如下
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import java.sql.SQLException;
public class ImageDataBase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "ImagesDatabase.db";
private static final String TABLE_NAME = "imagestore";
private static final String SQL_CREATE = "CREATE TABLE " + TABLE_NAME +
" (_id INTEGER PRIMARY KEY, IMAGETITLE TEXT , IMAGEURL TEXT , IMAGEDESC TEXT )";
private static final String SQL_DROP = "DROP TABLE IS EXISTS " + TABLE_NAME ;
ImageDataBase(Context context) {
super(context, DATABASE_NAME, null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(SQL_DROP);
onCreate(db);
}
public Cursor getImages(String id, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder sqliteQueryBuilder = new SQLiteQueryBuilder();
sqliteQueryBuilder.setTables(TABLE_NAME);
if(id != null) {
sqliteQueryBuilder.appendWhere("_id" + " = " + id);
}
if(sortOrder == null || sortOrder == "") {
sortOrder = "IMAGETITLE";
}
Cursor cursor = sqliteQueryBuilder.query(getReadableDatabase(),
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
return cursor;
}
public long addNewImage(ContentValues values) throws SQLException {
long id = getWritableDatabase().insert(TABLE_NAME, "", values);
if(id <=0 ) {
throw new SQLException("Failed to add an image");
}
return id;
}
public int deleteImages(String id) {
if(id == null) {
return getWritableDatabase().delete(TABLE_NAME, null , null);
} else {
return getWritableDatabase().delete(TABLE_NAME, "_id=?", new String[]{id});
}
}
public int updateImages(String id, ContentValues values) {
if(id == null) {
return getWritableDatabase().update(TABLE_NAME, values, null, null);
} else {
return getWritableDatabase().update(TABLE_NAME, values, "_id=?", new String[]{id});
}
}
}
在 AndroidManifest 中声明您的内容提供者
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidcontentproviderdemo.androidcontentprovider">
<application android:allowBackup="true" android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:theme="@style/AppTheme">
<provider android:name="com.androidcontentproviderdemo.androidcontentprovider.ImagesProvider" android:authorities="androidcontentproviderdemo.androidcontentprovider.images">
</provider>
</application>
</manifest>
使用内容提供者
public class MainActivity extends Activity {
private static final String PROVIDER_NAME = "androidcontentproviderdemo.androidcontentprovider.images";
private static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/images");
private ListView listView;
private SimpleCursorAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.lstViewImages);
adapter = new SimpleCursorAdapter(getBaseContext(),
R.layout.list_layout,
null,
new String[] { "IMAGETITLE", "IMAGEURL", "IMAGEDESC"},
new int[] { R.id.imgTitle , R.id.imgUrl, R.id.imgDesc }, 0);
listView.setAdapter(adapter);
refreshValuesFromContentProvider();
}
private void refreshValuesFromContentProvider() {
CursorLoader cursorLoader = new CursorLoader(getBaseContext(), CONTENT_URI,
null, null, null, null);
Cursor c = cursorLoader.loadInBackground();
adapter.swapCursor(c);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
public void onClickAddImage(View view) {
ContentValues contentValues = new ContentValues();
contentValues.put("IMAGETITLE", ((EditText) findViewById(R.id.edtTxtImageTitle)).getText().toString());
contentValues.put("IMAGEURL" , ((EditText)findViewById(R.id.edtImageUrl)).getText().toString());
contentValues.put("IMAGEDESC", ((EditText) findViewById(R.id.edtImageDesc)).getText().toString());
Uri uri = getContentResolver().insert(CONTENT_URI, contentValues);
Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show();
refreshValuesFromContentProvider();
}
}
SQL 每个应用程序的数据库都存储在它们存储上的私有文件夹中。所以路径如下。
/data/data/[app_package_name]/databases/[database_name]
应用程序无法使用 SQLite 数据库相互共享数据。
如果我们希望数据在其他应用程序之间共享,我们可以使用内容提供程序。
http://developer.android.com/reference/android/content/ContentProvider.html
我开发的应用程序中很少有通用功能,因此我创建了一个库来将通用代码放在一个点上。我在库中实现了 SQLite 数据库。
我的问题是图书馆的 SQLite 数据库会被应用程序共享吗? 我的意思是当从应用程序 A(使用公共库)插入 X 值时,是否也可以从应用程序 B(使用公共库)访问此数据。
我认为数据不会共享,因为每个应用程序都有自己的存储空间,数据只会保存在该存储空间中,这一点仍需澄清。
您可以将数据存储在私人应用程序文件夹之外,并从任何应用程序访问它。
如果您将数据存储在私有应用程序文件夹中,则只有在您拥有相同的 sharedUserId 时才能共享私有数据。应用程序必须使用相同的证书进行签名才能共享。
在应用程序之间共享数据的更好方法是创建一个 ContentProvider。它提供了与数据库类似的接口,并且可以通过应用程序权限提供访问限制。
您可以使用 ContentProviders
将数据从一个应用程序共享到 another.For 实例,方法是在您的应用程序中创建一个内容提供程序 class,它可以保存图像元数据项。我们将使用本地 SQLite 数据库来存储数据,但您可以使用任何您喜欢的地方来存储数据。
首先创建一个 ImagesProvider
class 扩展 ContentProvider
class 并覆盖以下方法。
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.net.Uri;
import android.util.Log;
public class ImagesProvider extends ContentProvider {
private static final String PROVIDER_NAME = "androidcontentproviderdemo.androidcontentprovider.images";
private static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/images");
private static final int IMAGES = 1;
private static final int IMAGE_ID = 2;
private static final UriMatcher uriMatcher = getUriMatcher();
private static UriMatcher getUriMatcher() {
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "images", IMAGES);
uriMatcher.addURI(PROVIDER_NAME, "images/#", IMAGE_ID);
return uriMatcher;
}
private ImageDatabase imageDataBase = null;
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case IMAGES:
return "vnd.android.cursor.dir/vnd.com.androidcontentproviderdemo.androidcontentprovider.provider.images";
case IMAGE_ID:
return "vnd.android.cursor.item/vnd.com.androidcontentproviderdemo.androidcontentprovider.provider.images";
}
return "";
}
@Override
public boolean onCreate() {
Context context = getContext();
imageDataBase = new ImageDatabase(context);
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
String id = null;
if(uriMatcher.match(uri) == IMAGE_ID) {
//Query is for one single image. Get the ID from the URI.
id = uri.getPathSegments().get(1);
}
return imageDataBase.getImages(id, projection, selection, selectionArgs, sortOrder);
}
@Override
public Uri insert(Uri uri, ContentValues values) {
try {
long id = imageDataBase.addNewImage(values);
Uri returnUri = ContentUris.withAppendedId(CONTENT_URI, id);
return returnUri;
} catch(Exception e) {
return null;
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
String id = null;
if(uriMatcher.match(uri) == IMAGE_ID) {
//Delete is for one single image. Get the ID from the URI.
id = uri.getPathSegments().get(1);
}
return imageDataBase.deleteImages(id);
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
String id = null;
if(uriMatcher.match(uri) == IMAGE_ID) {
//Update is for one single image. Get the ID from the URI.
id = uri.getPathSegments().get(1);
}
return imageDataBase.updateImages(id, values);
}
}
要存储内容,我们的内容提供商需要一个数据库助手 class。创建一个ImageDataBase
class如下
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import java.sql.SQLException;
public class ImageDataBase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "ImagesDatabase.db";
private static final String TABLE_NAME = "imagestore";
private static final String SQL_CREATE = "CREATE TABLE " + TABLE_NAME +
" (_id INTEGER PRIMARY KEY, IMAGETITLE TEXT , IMAGEURL TEXT , IMAGEDESC TEXT )";
private static final String SQL_DROP = "DROP TABLE IS EXISTS " + TABLE_NAME ;
ImageDataBase(Context context) {
super(context, DATABASE_NAME, null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(SQL_DROP);
onCreate(db);
}
public Cursor getImages(String id, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder sqliteQueryBuilder = new SQLiteQueryBuilder();
sqliteQueryBuilder.setTables(TABLE_NAME);
if(id != null) {
sqliteQueryBuilder.appendWhere("_id" + " = " + id);
}
if(sortOrder == null || sortOrder == "") {
sortOrder = "IMAGETITLE";
}
Cursor cursor = sqliteQueryBuilder.query(getReadableDatabase(),
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
return cursor;
}
public long addNewImage(ContentValues values) throws SQLException {
long id = getWritableDatabase().insert(TABLE_NAME, "", values);
if(id <=0 ) {
throw new SQLException("Failed to add an image");
}
return id;
}
public int deleteImages(String id) {
if(id == null) {
return getWritableDatabase().delete(TABLE_NAME, null , null);
} else {
return getWritableDatabase().delete(TABLE_NAME, "_id=?", new String[]{id});
}
}
public int updateImages(String id, ContentValues values) {
if(id == null) {
return getWritableDatabase().update(TABLE_NAME, values, null, null);
} else {
return getWritableDatabase().update(TABLE_NAME, values, "_id=?", new String[]{id});
}
}
}
在 AndroidManifest 中声明您的内容提供者
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidcontentproviderdemo.androidcontentprovider">
<application android:allowBackup="true" android:label="@string/app_name"
android:icon="@mipmap/ic_launcher" android:theme="@style/AppTheme">
<provider android:name="com.androidcontentproviderdemo.androidcontentprovider.ImagesProvider" android:authorities="androidcontentproviderdemo.androidcontentprovider.images">
</provider>
</application>
</manifest>
使用内容提供者
public class MainActivity extends Activity {
private static final String PROVIDER_NAME = "androidcontentproviderdemo.androidcontentprovider.images";
private static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/images");
private ListView listView;
private SimpleCursorAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.lstViewImages);
adapter = new SimpleCursorAdapter(getBaseContext(),
R.layout.list_layout,
null,
new String[] { "IMAGETITLE", "IMAGEURL", "IMAGEDESC"},
new int[] { R.id.imgTitle , R.id.imgUrl, R.id.imgDesc }, 0);
listView.setAdapter(adapter);
refreshValuesFromContentProvider();
}
private void refreshValuesFromContentProvider() {
CursorLoader cursorLoader = new CursorLoader(getBaseContext(), CONTENT_URI,
null, null, null, null);
Cursor c = cursorLoader.loadInBackground();
adapter.swapCursor(c);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
public void onClickAddImage(View view) {
ContentValues contentValues = new ContentValues();
contentValues.put("IMAGETITLE", ((EditText) findViewById(R.id.edtTxtImageTitle)).getText().toString());
contentValues.put("IMAGEURL" , ((EditText)findViewById(R.id.edtImageUrl)).getText().toString());
contentValues.put("IMAGEDESC", ((EditText) findViewById(R.id.edtImageDesc)).getText().toString());
Uri uri = getContentResolver().insert(CONTENT_URI, contentValues);
Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show();
refreshValuesFromContentProvider();
}
}
SQL 每个应用程序的数据库都存储在它们存储上的私有文件夹中。所以路径如下。
/data/data/[app_package_name]/databases/[database_name]
应用程序无法使用 SQLite 数据库相互共享数据。
如果我们希望数据在其他应用程序之间共享,我们可以使用内容提供程序。
http://developer.android.com/reference/android/content/ContentProvider.html