2010-08-08 15 views
8

A medida que la base de datos en mi aplicación crece, va a requerir más y más del espacio interno del teléfono. No hay datos confidenciales/privados en el DB, por lo que estoy interesado en moverlo a la tarjeta SD.¿Es posible mover el DB interno a la tarjeta SD?

Estoy usando SQLiteOpenHelper para ayudar con el trabajo de la base de datos. Tengo entendido que no puede usar esto para el acceso a bases de datos en la tarjeta SD, ya que no puede definir la ruta de la base de datos. Sin embargo, hay algunos ejemplos (muy pobres) en Internet que sugieren que puede anular esta limitación. Sin embargo, nunca obtuve uno de esos ejemplos de código para compilar.

¿Es posible? Y si es así, ¡CÓMO! Tenga en cuenta que la función "aplicaciones en la tarjeta SD" de Froyo no funcionará, ya que no mueve los archivos internos.

Respuesta

10

sólo tiene que utilizar:

SQLiteDatabase.openDatabase(DB_FULL_PATH, null, SQLiteDatabase.OPEN_READONLY); 

donde DB_FULL_PATH puede ser un camino hacia su sdcard, como /sdcard/mydatabase.db

Editar:

Esto es lo que llamo en mi solicitud de acceder a la base de datos ...

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; 
    } 
} 

... y esta es la clase de ayudante de db que estoy usando, que de hecho, se extiende SQLiteOpenHelper, por lo que todavía tendrá todo lo que desea de esta clase.

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) { 
    } 

} 
+0

No estoy seguro de que esto se puede utilizar junto con SQLiteOpenHelper. Lamentablemente, no estoy en mi área de trabajo ahora mismo y no puedo probar. Sin embargo, votará si es tan simple como eso. – GJTorikian

+3

¿Se pregunta por qué necesita explícitamente SQLiteOpenHelper? –

+0

Tiene un montón de métodos de ayuda para la creación de bases de datos y actualizaciones de bases de datos. No estoy familiarizado con una forma más simple de manejar esas acciones. – GJTorikian

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(); 

Para mí esto funciona, y se extiende WorkoutDBOpenHelper SQLiteOpenHelper y su constructor, simplemente llama a super para SQLiteOpenHelper.

WorkoutDBOpenHelper(Context context, String dbPath) { 
    super(context, dbPath, null, DATABASE_VERSION); 

} 

Tenga en cuenta que SQLiteopenHelper crea la base de datos en la tarjeta de memoria también. Sin embargo, en la desinstalación de la aplicación, la base de datos no se eliminará de la tarjeta SD.

Esta no es la respuesta de cómo mover un DB interno existente a una tarjeta SD, pero de esta manera puede elegir una opción en el momento de la creación. Estoy trabajando en mover la base de datos existente desde el directorio de "datos" de la aplicación a la tarjeta SD, pero no hay una forma directa. Se actualizará una vez que descubra algo.

1

Encontré que podría usar una ruta completa en Android 2.2, pero en 2.1 el método Context.openOrCreateDatabase() arrojó una excepción. Para solucionar este problema, envolví ese método para llamar directamente a SQLiteDatabase.openOrCreateDatabase(). Aquí está el constructor para mi SQLOpenHelper extendido

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; 
    } 
} 
0

Esto estará bien. Pensé

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(); 
} 
} 
Cuestiones relacionadas