Android数据库最佳实践

4

我的Android应用需要一个本地数据库。哪种方式最好?我该使用哪个类子类,子类,重新实现等。我在网上找到了太多的信息,但我仍然不知道哪些是最佳做法。

5个回答

7

这是一个相当广泛的问题,取决于您的经验和使用水平。

但是通常的做法是创建自己的ContentProvider,用来抽象数据库访问。这样,您可以使用Uri来执行选择/更新/删除/插入查询。

对于SQLite数据库本身,请使用SQLiteOpenHelper来抽象创建和升级SQLite数据库。这将使您能够轻松地升级您的数据库,而不会让用户失去所有数据。

我可以附上我在以前项目中使用的一段代码,帮助您入门。但是实现整个过程可能超出单个问题/答案的范围。

public class MyServiceProvider extends ContentProvider {
    private SQLiteDatabase db;

    @Override
    public boolean onCreate() {
        // Initialize the database and assign it to the private variable
        MyDatabaseHelper sqlHelper = new MyDatabaseHelper(getContext());
        db = sqlHelper.getReadableDatabase();

        return (db == null)?false:true;
    }

    @override
    Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        // handle the query here, form it, do your checks and then access the DB
        db.query(....);
    }
}

class MyDatabaseHelper extends SQLiteOpenHelper {
    private static final String LOG_TAG = "MyAppTag";
    private static final String DB_NAME = "Databasename";
    private static final String TABLE_NAME = "Tablename";
    private static final int DATABASE_VERSION = 2;
    public static MyServiceProvider.CONTENT_URI = Uri.parse("content://com.mycompany.myApp.MyAppService/myTableOrIdentifier");

    public MyDatabaseHelper(Context context){
        super(context, DB_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "CREATE TABLE IF NOT EXISTS ....";
        db.execSQL(sql);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // Here you can perform updates when the database structure changes
        // Begin transaction
        db.beginTransaction();

        try {
            if(oldVersion<2){
                // Upgrade database structure from Version 1 to 2
                String alterTable = "ALTER ....";

                db.execSQL(alterTable);
                Log.i(LOG_TAG,"Successfully upgraded to Version 2");
            }
            // This allows you to upgrade from any version to the next most 
            // recent one in multiple steps as you don't know if the user has
            // skipped any of the previous updates
            if(oldVersion<3){
                // Upgrade database structure from Version 2 to 3
                String alterTable = "ALTER ....";

                db.execSQL(alterTable);
                Log.i(LOG_TAG,"Successfully upgraded to Version 3");
            }

            // Only when this code is executed, the changes will be applied 
            // to the database
            db.setTransactionSuccessful();
        } catch(Exception ex){
            ex.printStackTrace();
        } finally {
            // Ends transaction
            // If there was an error, the database won't be altered
            db.endTransaction();
        }
    }
}

然后您可以使用游标与数据库进行交互。
ContentResolver contentResolver = getContentResolver();
...
Cursor c = contentResolver.query(
        // The Uri results in content://com.mycompany.myApp.MyAppService/myTableOrIdentifier/someId
        Uri.withAppendedPath(MyServiceProvider.CONTENT_URI, someId),
        new String[] {
            // only get fields we need!
            "MyDbFieldIneed"
        },
        null, null, null);

这将返回一个Cursor,您可以迭代它并获取结果。这也是Android中大多数事物的实现方式(例如,从地址簿获取地址也是通过Uri和Cursor实现的)。 编辑: 我意识到代码高亮使链接难以看到。这里是您需要的重要类的链接:

编辑2: 如果你处理多个表格,UriMatcher 也是一个重要的资源


谢谢。你能给我展示一下如何声明contentResolver对象的例子吗? - Didac Perez Parera
很简单。getContentResolver()Context 的一个方法,而 Activity 继承自 Context(实际上 Activity 继承自 ContextThemeWrapper,后者继承自 ContextWrapper,再后者继承自 Context)。因此,一个简单的 ContentResolver contentResolver = getContentResolver(); 就可以完成它。 - Tseng

4
我认为最好的使用SQLite数据库的方式是使用ContentProviders。当你搜索时,会发现ContentProvider API非常复杂。但有一个非常好的库,可以使这个过程变得非常容易。它被称为ProviGen,并且您可以在下面的链接中找到详细信息。

https://github.com/TimotheeJeannin/ProviGen

使用起来非常简单。您只需创建一个Contract类,使用注释指示您需要在数据库中使用哪些列,它将自动创建所有内容。我甚至可以在一个数据库中创建多个表。


ContentProvider 得到了 +1 的赞。但我不同意它们很复杂的说法。一旦你掌握了,它就非常简单。它只需要更多的代码来启动,但这对大多数模式都是有效的。MVVM/MVC 模式在一开始也需要相当多的代码,但它们是有效的模式,并且后期易于维护。 - Tseng
当您的SQLite数据库中有2或3个表与ContentProvider相关联时,事情变得更加复杂。ProviGen可以自动完成这项工作。 - tasomaniac

2
我认为最好的做法是使用框架,它会为您完成大部分工作。在处理数据库时,我个人更喜欢ORM映射,因此建议尝试一些ORM框架。我所知道的最好的一个是OrmLite。作者还在这里回答问题,这非常有用。
但如果你不想使用它,你应该先阅读这些文章:


1

哪种方式最好?
您需要使用Android自带的SQLite。每个Android应用程序都可以拥有自己的数据库。

我该使用哪个类子类或重新实现?
您需要扩展SQLiteOpenHelper类,它确定您的数据库名称、如何升级/降级、表结构等。 它还定义了获取对数据库引用的方法。

是的,有很多资源可供使用,但并非所有资源都友好且质量良好。这里有一些我喜欢的:
Lars Vogel的SQLite和ContentProvider
Gustin教授的Android教程

至于您的问题标题Android数据库的最佳实践,我只能说适用于SQL数据库的所有最佳实践也适用于此,例如规范化等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接