一个APP多个数据库

最近在项目中碰到一个新的模块,添加IM功能,在原有账号基层上添加一个IM账号,IM聊天的信息也需要保存在本地;

我们的做法是每个IM账号新建一个db文件,各自账号的消息存放在各自的数据库文件中,这样的好处是可以减小数据库文件的大小,查询数据的时候效率比较高。

不过这种做法的有一个需要注意的地方就是,

  1. 每次账号切换的时候需要重新加载数据库实例对象,不能把对象写死成 static class的类型,每次退出账号的时候要重置数据库实例对象,登录的时候新建。
  2. 若数据库是操作方法是以接口方法来做的话,在实例里面必须动态获取SQLiteOpenHelper对象,不要把它写成私有的成员变量。

具体实现步骤:

一、实现SQLiteOpenHelper类
public class DBHelper extends SQLiteOpenHelper {
    private static final int VERSION = 1;//数据库版本号

    //用户IM历史记录表
    private final String tUserImInfo = "create table if not exists useriminfo (" +
            "id         integer primary key autoincrement," +
            "msgid      text primary key not null," +
            "caseid     text")";

    //用户IM历史记录视图
    private final String vUserImInfo = "create view vuseriminfo as "
            + "select * from useriminfo order by caseid,timestamp desc,isim";


    private static DBHelper helper;

    private DBHelper(Context context) {
        super(context, getDBName(), null, VERSION);
    }

    /**
     * 数据库名字
     *
     * @return
     */
    private static String getDBName() {
        return "im_" + PreferenceUserBean.getUserId() + ".db";
    }

    /**
     * 获取一个SQLiteOpenHelper的实例
     *
     * @return
     */
    public static DBHelper getInstance() {
        if (null == helper) {
            synchronized (DBHelper.class) {
                if (null == helper) {
                    helper = new DBHelper(IBingLiApplcation.getApplcationContext());
                }
            }
        }
        return helper;
    }


    /**
     * 当用户退出、或被挤出APP,当换用户登录的时候就需要切换数据库,这时就需要重新建数据库
     *
     * @return
     */
    public static void closeDBHelper() {
        if (null != helper) {
            helper.close();
        }
        helper = null;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(tUserImInfo);
        db.execSQL(vUserImInfo);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //逐级迭代更新,防止跨版本更新的时候造成数据库不一致
        switch (oldVersion) {
            case 1:
                version1To2(db);
            case 2:
                version2To3(db);
                break;
        }
    }
}

采坑解析:

一开始的时候,没有注意到,我用的是一个静态内部类做的一个单实例,这样的话每次切换用户的时候,就不会在实例化一个对象,导致没有办法切换数据库。

错误代码:

public class DBHelper extends SQLiteOpenHelper {

	private static class SingleHolder{
		private static final DBHelper helper=new DBHelper();
	}
	
	private DBHelper getInstance(){
		return SingleHolder.helper;
	}
}

二、数据库接口实现

我采用接口的方法来统一处理增删改查的具体逻辑,这样方便扩展,也方便维护

public class IMInfoDaoImpl implements IMInfoDao {

    private DBHelper getHelper() {
        return DBHelper.getInstance();
    }

    @Override
    public int queryUnReadCountByCaseID(String id) {
        int total = 0;
        String sql = "select count(*) total from tableName where status=0 and id=?";
        String[] args = new String[]{id};
        SQLiteDatabase db = getHelper().getReadableDatabase();
        Cursor cursor = db.rawQuery(sql, args);
        while (cursor.moveToNext()) {
            total = cursor.getInt(cursor.getColumnIndex("total"));
        }
        cursor.close();
        db.close();
        return total;
    }

    @Override
    public int queryUnReadCountByCaseType(int type) {
        int total = 0;
        String sql = "select count(*) total from tableName where status=0 and type=?";
        String[] args = new String[]{String.valueOf(type)};
        SQLiteDatabase db = getHelper().getReadableDatabase();
        Cursor cursor = db.rawQuery(sql, args);
        if (cursor.moveToNext()) {
            total = cursor.getInt(cursor.getColumnIndex("total"));
        }
        cursor.close();
        db.close();
        return total;
    }
    …………………………………………………………
}

采坑解析:

刚开始,我获取DBHelper对象实例的时候是在IMInfoDaoImpl中写了是有成员变量,在new IMInfoDaoImpl()方法的时候就初始化了,这样做的后果就是,每当我退出账号A,不杀死APP的情况下,登录账号B,发现此时此刻明明已经加载了B的数据库,但是账号B的相关聊天数据,就是写到了A的库里面去了,这个问题纠结了我好几天,最后找到了这里DBHelper的对象必须动态获取,不能写成私有成员,每次都通过DBHelper.getInstance()去获取最新的对象。

错误代码:

public class IMInfoDaoImpl implements IMInfoDao {
	private DBHelper helpser;
	
	public IMInfoDaoImpl(){
		helpser=DBHelper.getInstance();
	}

    @Override
    public int queryUnReadCountByCaseType(int type) {
        int total = 0;
        String sql = "select count(*) total from tableName where status=0 and type=?";
        String[] args = new String[]{String.valueOf(type)};
        SQLiteDatabase db = helpser.getReadableDatabase();
        Cursor cursor = db.rawQuery(sql, args);
        if (cursor.moveToNext()) {
            total = cursor.getInt(cursor.getColumnIndex("total"));
        }
        cursor.close();
        db.close();
        return total;
    }
    …………………………………………………………
}

三、账号登出时置空DBHelper对象,释放相关资源

DBHelper.closeDBHelper()

在此过程中,让我纠结郁闷很久的地方就是IMInfoDaoImpl里面DBHelper对象的问题,一开始写代码的时候没有意思到账号切换的问题,导致后来一系列的问题,用户收到了消息,再次登录历史记录又没有显示出来等问题,这里主要是动态获取DBHelper的对象就好了。




你可能感兴趣的:(android)