随着我应用中数据库的增长,它将需要越来越多的内部手机空间。数据库中没有任何敏感/私人数据,因此我有兴趣将其移至SD卡。
我正在使用SQLiteOpenHelper来协助数据库工作。我的理解是,您不能将其用于SD卡上的DB访问,因为您无法定义数据库路径。但是,Internet上有一些(非常差的)示例表明您可以覆盖此限制。但是我从来没有得到其中一个代码示例来编译。
有可能吗?如果是这样 - 怎么样!请注意,Froyo的“SD卡上的应用程序”功能不起作用,因为它不会移动内部文件。
答案 0 :(得分:10)
只需使用:
SQLiteDatabase.openDatabase(DB_FULL_PATH, null, SQLiteDatabase.OPEN_READONLY);
其中DB_FULL_PATH可以是sdcard的路径,例如/sdcard/mydatabase.db
编辑:
这是我在我的应用程序中调用的数据库....
private static DBUtil dbHelper = null;
public void openDatabase() {
if(dbHelper == null) {
dbHelper = new DBUtil(this.context);
dbHelper.openDataBase(SQLiteDatabase.OPEN_READWRITE);
}
}
public void closeDatabase() {
if(dbHelper != null) {
dbHelper.close();
dbHelper = null;
}
}
...这是我正在使用的db帮助程序类,它实际上扩展了SQLiteOpenHelper,因此您仍然可以从此类中获得所需的一切。
package com.myapp.android.db;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.myapp.android.MyApp;
import java.io.IOException;
/**
* Standard database utility class.
*
* TODO: Refactor.
*/
public class DBUtil extends SQLiteOpenHelper {
/**
* Database directory.
*
* <p>
* Example: "/sdcard/myapp/db/"
* </p>
*/
public static String DB_DIRECTORY = null;
/**
* Name of the database file.
*
* <p>
* Example: "mydatabase.db"
* </p>
*
*/
public static String DB_NAME = null;
/**
* Full absolute path of the database.
*
* <p>
* Example: "/sdcard/myapp/db/mydatabase.db"
* </p>
*/
public static String DB_FULL_PATH = null;
static {
DB_DIRECTORY = MyApp.DATA_REPOSITORY_URI + "/myapp/db/";
DB_NAME = "mydatabase.db";
DB_FULL_PATH = DB_DIRECTORY + DB_NAME;
}
private SQLiteDatabase myDataBase;
/**
* Constructor Takes and keeps a reference of the passed context in order to
* access to the application assets and resources.
*
* @param context
*/
public DBUtil(Context context) {
super(context, DB_NAME, null, 1);
try {
this.createDataBase();
} catch (IOException ioe) {
throw new Error("Unable to create database");
}
}
/**
* Creates a empty database on the system and rewrites it with your own
* database.
* */
public void createDataBase() throws IOException {
if (!checkDataBase()) this.getWritableDatabase();
}
/**
* Check if the database already exist to avoid re-copying the file each
* time you open the application.
*
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
checkDB = SQLiteDatabase.openDatabase(DB_FULL_PATH, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
// database does't exist yet.
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
public void openDataBase(int mode) throws SQLException {
try {
myDataBase = SQLiteDatabase.openDatabase(DB_FULL_PATH, null, mode);
} catch(IllegalStateException e) {
// Sometimes, esp. after application upgrade, the database will be non-closed, raising a IllegalStateException
// below. Try to avoid by simply opening it again.
Log.d(MyApp.APP, "Database non-closed. Reopening.");
myDataBase = SQLiteDatabase.openDatabase(DB_FULL_PATH, null, mode);
}
}
public void openDataBase() throws SQLException {
openDataBase(SQLiteDatabase.OPEN_READWRITE);
}
public SQLiteDatabase getDb() {
return myDataBase;
}
@Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
答案 1 :(得分:1)
我发现我可以在Android 2.2中使用完整路径,但在2.1中,Context.openOrCreateDatabase()方法引发了异常。为了解决这个问题,我将该方法包装成直接调用SQLiteDatabase.openOrCreateDatabase()。这是我的扩展SQLOpenHelper
的构造函数public class Database extends SQLiteOpenHelper {
public Database(Context context) {
super(new ContextWrapper(context) {
@Override public SQLiteDatabase openOrCreateDatabase(String name,
int mode, SQLiteDatabase.CursorFactory factory) {
// allow database directory to be specified
File dir = new File(DIR);
if(!dir.exists()) {
dir.mkdirs();
}
return SQLiteDatabase.openDatabase(DIR + "/" + NAME, null,
SQLiteDatabase.CREATE_IF_NECESSARY);
}
}, NAME, null, VERSION);
this.context = context;
}
}
答案 2 :(得分:0)
String dbPath = DATABASE_NAME;
File sdcard = Environment.getExternalStorageDirectory();
if (sdcard != null && sdcard.canWrite()){
dbPath = sdcard.getAbsolutePath() + "/mypath/onsdcard/" + DATABASE_NAME;
}
else {
dbPath = DATABASE_NAME;
}
mDBHelper = new WorkoutDBOpenHelper(context, dbPath);
if(null != mDBHelper)
mDB = mDBHelper.getWritableDatabase();
对我来说这很有用,WorkoutDBOpenHelper扩展了SQLiteOpenHelper,它的构造函数只是为SQLiteOpenHelper调用super。
WorkoutDBOpenHelper(Context context, String dbPath) {
super(context, dbPath, null, DATABASE_VERSION);
}
请注意,SQLiteopenHelper也会在存储卡上创建数据库。 但是,在应用程序卸载时,不会从SD卡中删除数据库。
这不是如何将现有内部数据库移动到SDCard的答案,但这样您就可以在创建时选择一个选项。我正在努力将已经存在的数据库从应用程序的“数据”目录移动到SD卡,但没有直接的方法。一旦我找到了什么就会更新。
答案 3 :(得分:0)
这没关系。我想
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("DATABASE EXIST : ", ""+checkDataBase());
if(!checkDataBase())
copyDataBase();
DatabaseHandler dbhandler = new DatabaseHandler(MainActivity.this);
Cursor cursor = dbhandler.getAllContacts();
ListView list = (ListView) findViewById(R.id.datalist);
CustomCursorAdapter cursoradapter = new CustomCursorAdapter(MainActivity.this, cursor);
list.setAdapter(cursoradapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private void copyDataBase()
{
ContextWrapper cw =new ContextWrapper(getApplicationContext());
String DB_PATH = "/data/data/com.example.copydatabase/databases/";
String DB_NAME = "testing";
Log.i("Database", "New database is being copied to device!");
byte[] buffer = new byte[1024];
OutputStream myOutput = null;
int length;
// Open your local db as the input stream
InputStream myInput = null;
try
{
myInput = MainActivity.this.getAssets().open(DB_NAME);
// transfer bytes from the inputfile to the
// outputfile
myOutput =new FileOutputStream(DB_PATH+ DB_NAME);
while((length = myInput.read(buffer)) > 0)
{
myOutput.write(buffer, 0, length);
}
myOutput.close();
myOutput.flush();
myInput.close();
Log.i("Database", "New database has been copied to device!");
}
catch(IOException e)
{
e.printStackTrace();
}
}
public boolean checkDataBase()
{
String DB_PATH = "/data/data/com.example.copydatabase/databases/";
String DB_NAME = "testing";
File dbFile = new File(DB_PATH + DB_NAME);
return dbFile.exists();
}
}