如何在更新 android 应用程序时用新数据库完全替换旧的 sqlite 数据库?

Posted

技术标签:

【中文标题】如何在更新 android 应用程序时用新数据库完全替换旧的 sqlite 数据库?【英文标题】:How do I completely replace the old sqlite database with new one on update of android app? 【发布时间】:2018-04-24 04:23:27 【问题描述】:

我的应用程序版本 1.0 有一个 SQLite 数据库,其中包含离线数据存储。目的是用户可以在没有互联网离线的情况下搜索一些主题。现在在下一次更新中,我想将我的应用程序同步到 Web 服务,这样如果 Web 服务上更新了新主题,那么我的应用程序会自动下载它们并存储在本地 SQLite 数据库中。对于这个新场景,我需要修改旧表以及创建一些新表。但是对于旧表我只想添加一些字段并且不想丢失我的旧数据。所以现在我想,在我的下一次更新中,应用程序将删除以前的 SQLite 数据库并用这个新数据库替换。我读了this question,但被 cmets 弄糊涂了,他们正在谈论删除旧表和创建新表。但是在这种情况下,如何手动将我太多的旧数据插入新表中。

下面是我正在使用的 DBHelper 类:

public class DBHelper extends SQLiteOpenHelper 

    public static String DB_PATH = "/data/data/com.example.myapp/databases/";
    public static String DB_NAME = "myapp.db";
    public static final int DB_VERSION = 1;

    public static final String TB_TOPICS = "My_Topics";

    private SQLiteDatabase myDB;
    private Context context;

    public DBHelper(Context context) 
        super(context, DB_NAME, null, DB_VERSION);
        this.context = context;
    

    @Override
    public void onCreate(SQLiteDatabase db) 
        // TODO Auto-generated method stub

    

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
        // TODO Auto-generated method stub

    

    @Override
    public synchronized void close()
        if(myDB!=null)
            myDB.close();
        
        super.close();
    

    /***
     * Open database
     * @throws SQLException
     */
    public void openDataBase() throws SQLException
        String myPath = DB_PATH + DB_NAME;
        myDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
    

    /***
     * Copy database from source code assets to device
     * @throws IOException
     */
    public void copyDataBase() throws IOException
        try 
            InputStream myInput = context.getAssets().open(DB_NAME);
            String outputFileName = DB_PATH + DB_NAME;
            OutputStream myOutput = new FileOutputStream(outputFileName);

            byte[] buffer = new byte[1024];
            int length;

            while((length = myInput.read(buffer))>0)
                myOutput.write(buffer, 0, length);
            

            myOutput.flush();
            myOutput.close();
            myInput.close();
         catch (Exception e) 
            Log.e("tle99 - copyDatabase", e.getMessage());
        

    

    /***
     * Check if the database doesn't exist on device, create new one
     * @throws IOException
     */
    public void createDataBase() throws IOException 
        boolean dbExist = checkDataBase();

        if (dbExist) 

         else 
            this.getReadableDatabase();
            try 
                copyDataBase();
             catch (IOException e) 
                Log.e("tle99 - create", e.getMessage());
            
        
    

    // ---------------------------------------------
    // PRIVATE METHODS
    // ---------------------------------------------

    /***
     * Check if the database is exist on device or not
     * @return
     */
    private boolean checkDataBase() 
        SQLiteDatabase tempDB = null;
        try 
            String myPath = DB_PATH + DB_NAME;
            tempDB = SQLiteDatabase.openDatabase(myPath, null,
                    SQLiteDatabase.OPEN_READWRITE);
         catch (SQLiteException e) 
            Log.e("tle99 - check", e.getMessage());
        
        if (tempDB != null)
            tempDB.close();
        return tempDB != null ? true : false;
    

下面是我从活动方法调用数据库的方法:

List<AVData> listAVData = new ArrayList<AVData>();
    DBHelper dbHelper = new DBHelper(this);
    try 
        dbHelper.createDataBase();
     catch (IOException e) 
        e.printStackTrace();
    
    listAVData = dbHelper.getHeadings(topicToSearch.trim());

【问题讨论】:

SQLiteOpenHelper#onUpgrade: 当数据库需要升级时调用。实现应使用此方法删除表、添加表或执行升级到新架构版本所需的任何其他操作。 【参考方案1】:

试试吧。

在 SQLITEOpenHelper 类中

public class YourHelperClassName extends SQLiteOpenHelper 

    public YourHelperClassName(Context c) 
            super(c, "YOUR_DBNAME", null, new_version_number);
        

    @Override
    public void onCreate(SQLiteDatabase db) 
        //Add the Table creation code for new version here. Since this code works for the new user or when the user cleare data from settings.
    

然后在其中 OverRide onUpgrade 方法并执行

@Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
        if (oldVersion == your_old-version_number && newVersion == new_version_number) 

     //1.Fetch Data from old table and Assign it in a Cursor.
     //2.Drop the table and Create New Table or Alter the Table.
     //3.Add data to the new table from the Cursor.
     // If you are Altering the table it is not required to add the data again to the table



希望这可以帮助您解决问题。使用现有数据库进行升级比创建新数据库更好。您可以使用您的逻辑进行升级。不要在升级数据库代码时将onCreate代码更改为新代码。

【讨论】:

以上是关于如何在更新 android 应用程序时用新数据库完全替换旧的 sqlite 数据库?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Avangate 设置定期订阅

如何在运行时用 ChildFragmentManager 和没有 PagerSlidingTabStrip Xamarin.Android 标题的片段替换片段

Swift 用新数据更新 UITableView

用新的位置数据更新核心数据(神奇的记录)

用新数据更新 SVM 分类器

React:“PrevState”和“=>”的代码解释[重复]