SQLiteOpenHelper使用指定位置数据库

在Android项目中,为了方便数据库文件的导出与分析,需要将SQLiteOpenHelper创建的数据库放置在指定位置。针对Android 6.0系统,通过继承ContextWrapper创建DatabaseContext类,并重写相关方法来改变数据库路径。同时,为了实现外部存储的读写,需要处理6.0及以上版本的动态权限申请。完成以上步骤,可以成功在指定路径创建SQLite数据库。

SQLiteOpenHelper使用指定位置数据库

目标和环境

最近项目中需要事实存储监测的数据,于是使用SQLiteOpenHelper来实现。事后又要导出到分析软件分析,所以必须将db文件放到指定的位置。SQLiteOpenHelper默认的位置只有app自己访问,想导出来很麻烦。一番搜索和试错后,终于实现功能。手机版本是android6.0,studio3.5.2。

虽然csdn上面能看到不少相关的文章,奈何google更猛。所以好多文章照着做也是失败。最后终于在stackoverflow这个问题下面k3b大佬的回复找到了解决方法。

代码

自己写的SQLiteOpenHelper类中间要有如下的改动:

public class DatabaseHelper extends SQLiteOpenHelper {
  private static final int DATABASE_VERSION = 3;
    .....

  DatabaseHelper(final Context context, String databaseName)  {
    super(new DatabaseContext(context), databaseName, null, DATABASE_VERSION);
  }
}

创件一个DatabaseContext类继承ContextWrapper并重写getDatabasePath和openOrCreateDatabase

class DatabaseContext extends ContextWrapper {

  private static final String DEBUG_CONTEXT = "DatabaseContext";

  public DatabaseContext(Context base) {
    super(base);
  }

  @Override
  public File getDatabasePath(String name)  {
    File sdcard = Environment.getExternalStorageDirectory();    
    String dbfile = sdcard.getAbsolutePath() + File.separator+ "databases" + File.separator + name;
    if (!dbfile.endsWith(".db")) {
      dbfile += ".db" ;
    }

    File result = new File(dbfile);

    if (!result.getParentFile().exists()) {
      result.getParentFile().mkdirs();
    }

    if (Log.isLoggable(DEBUG_CONTEXT, Log.WARN)) {
      Log.w(DEBUG_CONTEXT, "getDatabasePath(" + name + ") = " + result.getAbsolutePath());
    }

    return result;
  }

  /* this version is called for android devices >= api-11. thank to @damccull for fixing this. */
  @Override
  public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
    return openOrCreateDatabase(name,mode, factory);
  }

  /* this version is called for android devices < api-11 */
  @Override
  public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
    SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
    // SQLiteDatabase result = super.openOrCreateDatabase(name, mode, factory);
    if (Log.isLoggable(DEBUG_CONTEXT, Log.WARN)) {
      Log.w(DEBUG_CONTEXT, "openOrCreateDatabase(" + name + ",,) = " + result.getPath());
    }
    return result;
  }
}

理论上这样就能在指定的位置创建db文件了。

权限

光上面的代码还是不行的,还需要外部存储文件的读写权限,6.0以前只要在manifest里面添加下面这些代码

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

6.0及以上的就要动态申请。
首先写一个申请类

public class PermissionUtils {

    private static String[] PERMISSIONS_CAMERA_AND_STORAGE = {
            android.Manifest.permission.READ_EXTERNAL_STORAGE,
            android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
            android.Manifest.permission.CAMERA};

      public static boolean isGrantExternalRW(Activity activity, int requestCode) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            int storagePermission = activity.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
            int cameraPermission = activity.checkSelfPermission(android.Manifest.permission.CAMERA);
                  if (storagePermission != PackageManager.PERMISSION_GRANTED ||
                    cameraPermission != PackageManager.PERMISSION_GRANTED) {
                     activity.requestPermissions(PERMISSIONS_CAMERA_AND_STORAGE, requestCode);
                  return false;
            }
        }
        return true;
    }
}

之后在MainActivty的onCreate下添加

 PermissionUtils.isGrantExternalRW(this,1);

运行的时候授权就ok了。

关于路径

现在很多手机没有sd卡,但是依然有外部存储。只能APP访问的,就是内部存储,反之,应该是外部存储了。
不管是不是存在sd卡上,注意用正确的get方法拿到正确的路径。我这里是用Environment.getExternalStorageDirectory().getAbsolutePath()拿到根目录的。
否则很容易看到android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (Sqlite code 14)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值