在createMethod上使用同步Sqlite的asyn方法

时间:2017-11-22 15:45:46

标签: sqlite xamarin xamarin.android

我正在使用Xamarin,我的SQLite表也包含大量数据。

因为我想避免OnCreate()中的UIThread问题,我需要异步执行数据库操作。

如果我正确处理这个问题,我正在寻找指导。

第一种方法,我在网上找到了:

protected override void OnCreate(Bundle savedInstanceState)
{           
    base.OnCreate(savedInstanceState);

    SetContentView(Resource.Layout.InventoryPreviewMain);

    Thread thread = new Thread(() =>
    {
        SQLiteConnection db = new SQLiteConnection(dpPath);

        var table = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + Connection.CategoryID + "");

        mItems = new List<InventoryPreviewClass>();

        foreach (var item in table)
        {
            mItems.Add(new InventoryPreviewClass() { InventoryItemID = item.InventoryItemID, InventoryItemName = item.InventoryItemName, InventoryItemPrice = item.InventoryItemPrice });
        }

        MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
        mlistview.Adapter = adapter;
    });
    thread.Start();

第二种方法,使用async

public async void StartTimer()
{
    SQLiteConnection db = new SQLiteConnection(dpPath);

    var table = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + Connection.CategoryID + "");

    mItems = new List<InventoryPreviewClass>();

    foreach (var item in table)
    {
        mItems.Add(new InventoryPreviewClass() { InventoryItemID = item.InventoryItemID, InventoryItemName = item.InventoryItemName, InventoryItemPrice = item.InventoryItemPrice });
    }

    MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
    mlistview.Adapter = adapter;

    await Task.Delay(500);
}

两个示例中的哪一个对于保持活动UIthread更安全?有没有其他解决方案可以做到这一点?还有什么可以做的?

1 个答案:

答案 0 :(得分:0)

答案

使用Cross-platform SQLite Library制作的@FrankKruger为Xamarin移动应用创建/访问SQLite数据库。

这个库有一个内置的异步连接,所以你永远不必担心再次从UI线程访问数据库!

Xamarin.Android示例

“第二种方法”

public async Task StartTimer()
{
    mItems = await InventoryPreviewClassDatabase.GetAllInventoryPreviewClassAsync();

    MyListViewAdapterInventory adapter = new MyListViewAdapterInventory(this, Resource.Layout.InventoryPreview, mItems);
    mlistview.Adapter = adapter;
}

BaseDatabase Class

using System;
using System.Threading.Tasks;

using SQLite;

namespace SampleApp
{
    public abstract class BaseDatabase
    {
        #region Constant Fields
        static readonly Lazy<SQLiteAsyncConnection> _databaseConnectionHolder = new Lazy<SQLiteAsyncConnection>(() => GetDatabaseConnection());
        #endregion

        #region Fields
        static bool _isInitialized;
        #endregion

        #region Properties
        static SQLiteAsyncConnection DatabaseConnection => _databaseConnectionHolder.Value;
        #endregion

        #region Methods
        protected static async Task<SQLiteAsyncConnection> GetDatabaseConnectionAsync()
        {
            if (!_isInitialized)
                await Initialize().ConfigureAwait(false);

            return DatabaseConnection;
        }

        static async Task Initialize()
        {
            await DatabaseConnection.CreateTableAsync<InventoryPreviewClass>().ConfigureAwait(false);
            _isInitialized = true;
        }

        SQLiteAsyncConnection GetDatabaseConnection()
        {
            var sqliteFilename = "YourDatabaseName.db3";
            string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
            var path = Path.Combine(documentsPath, sqliteFilename);

            var conn = new SQLiteAsyncConnection(path, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.SharedCache);

            return conn;
        }
        #endregion

    }
}

父数据库类

using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace SampleApp
{
    public abstract class InventoryPreviewClassDatabase : BaseDatabase
    {
        #region Methods    
        public static async Task<IList<InventoryPreviewClass>> GetAllInventoryPreviewClassAsync()
        {
            var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);

            return await databaseConnection.Table<InventoryPreviewClass>().ToListAsync().ConfigureAwait(false);
        }

        public static async Task<InventoryPreviewClass> GetInventoryPreviewClassByIDAsync(int id)
        {
            var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);

            return await databaseConnection.Table<InventoryPreviewClass>().Where(x => x.ID.Equals(id)).FirstOrDefaultAsync().ConfigureAwait(false);
        }

        public static async Task<int> SaveInventoryPreviewClassAsync(InventoryPreviewClass inventoryPreview)
        {
            var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);

            var isObjectInDatabase = await GetInventoryPreviewClassByIDAsync(inventoryPreview.ID).ConfigureAwait(false) != null;

            if (isObjectInDatabase)
                return await databaseConnection.UpdateAsync(inventoryPreview).ConfigureAwait(false);

            return await databaseConnection.InsertAsync(inventoryPreview).ConfigureAwait(false);
        }

        public static async Task<int> DeleteItemAsync(OpportunityModel opportunity)
        {
            var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);

            return await databaseConnection.DeleteAsync(opportunity).ConfigureAwait(false);
        }

        public static async Task<int> GetNumberOfRowsAsync()
        {
            var databaseConnection = await GetDatabaseConnectionAsync().ConfigureAwait(false);

            return await databaseConnection.Table<InventoryPreviewClass>().CountAsync().ConfigureAwait(false);
        }
        #endregion
    }
}

此代码的灵感来自this Xamarin.Forms sample app