等待C#

时间:2015-06-17 13:02:29

标签: c# asynchronous async-await task

我花了好几个小时 - 如果不是几天 - 关于以下看似简单的问题。

我正在开发一个Xamarin-app,它通过调用webservice来从后端使用数据。它还会在下载后将这些数据存储在内部SQLite-Database中,以避免不必要的Web服务调用。如果后端的数据已更新,则在第一个应用程序启动时下载一次数据,然后仅更新数据。

假设我有一个存储库,它将通过调用webservice或(同步)从内部SQLite-Database从后端(异步)加载数据。存储库负责传递数据,无论数据来源如何。存储库将数据的对象引用存储在可以公开访问的内部列表中。存储库是一个通用的抽象类,它只是由实现类子类化以提供有关Type的信息。所有与后端同步的逻辑都封装在存储库中(据我所知,这是存储库模式)

构建存储库后,通过调用Load()方法加载它。此方法是异步的,因为它执行以下操作:

  • 获取后端中最后一次修改的日期。只有在应用程序启动后才会执行此操作。最后修改日期存储为属性。
  • 通过调用GetAll() - 方法存储数据的对象引用。此方法标记为异步,可以是异步或同步的,具体取决于数据的加载位置(请参阅下面的代码)
    • 如果数据已过时,则首先通过调用Web服务下载最新数据。然后将下载的数据存储在内部SQLite数据库中,替换所有以前下载的数据。
    • 在(如果有的话)数据已经下载之后,GetAll() - 方法通过查询SQLite数据库来返回数据。这是SQLite.NET-Package提供的同步调用。

什么不起作用(以及我不理解的)是以下行为:

  • 第一次加载存储库时(即NeedsUpdate返回true,一切正常。到目前为止一切顺利。
  • 在所有后续调用(= app starts)中加载存储库会导致System.NullReferenceException异常。调试代码表明Refresh() - 方法确实没有从GetAll()调用(=预期的行为)。

我知道您不应该使用async void方法,并且标记为async的方法应始终返回Task。显然,后者在我的代码中并非如此。那么我怎样才能做到这一点呢?

这是我的代码:

BasViewModel.cs(在存储库上调用Load())

public abstract class BaseViewModel<T> : MvxViewModel
{
    protected IRepository<T> Repository;

    public virtual async Task Init()
    {
        if (Repository != null)
        {
            await Repository.Load();                
        }                
    }
}

Repository.cs

 public abstract class Repository<T> : IRepository<T>

    protected List<T> ItemList = new List<T>();
    public List<T> Items
    {
        get { return ItemList; }
        set
        {                
            ItemList = value;
            if (ItemsChanged != null)
                ItemsChanged(this, ItemList);
        }
    }

    public virtual async Task Load()
    {
        if (CurrentUpdate.Equals(DateTime.MaxValue) || CurrentUpdate.Equals(DateTime.MinValue))
            CurrentUpdate = await WebService.Status(exception => { });
        Items = await GetAll();
    }

    public virtual async Task<List<T>> GetAll()
    {
        if (NeedsUpdate)
            await Refresh();

        return DbService.All();
    }

    public async Task Refresh()
    {
        var result = await WebService.DoGet(error => { });
        if (ItemsDownloaded != null)
            ItemsDownloaded(this, result);
        ReloadDatabase(result);
    }

    protected void ReloadDatabase(IEnumerable<T> items)
    {
        DbService.DeleteAll();
        foreach (var item in items)
        {
            DbService.Insert(item);
        }
        LastUpdate = DateTime.Now;
        FileService.WriteFile(FileName, LastUpdate.ToString());
    }
}

DatabaseService.cs

public abstract class DatabaseService<T> {
    public List<T> All()
    {
        // ISQLiteConnection was instantiated before
        return Connection.Table<T>().ToList();
    }
}

WebService.cs

public abstract class WebService<T>
    public virtual async Task<List<T>> DoGet(Action<Exception> error)
    {
        using (var client = new HttpClient())
        {
            string result = await client.GetStringAsync("http://example.com/myApi");
            return JsonConvert.DeserializeObject<T>(result);
        }
    }
 }

堆栈跟踪

06-17 14:21:43.701 D/AndroidRuntime( 2897): Shutting down VM
The thread 'Unknown' (0x4) has exited with code 0 (0x0).
An unhandled exception occured.

06-17 14:21:45.760 E/AndroidRuntime( 2897): FATAL EXCEPTION: main
06-17 14:21:45.760 E/AndroidRuntime( 2897): Process: ch.bbv.fumetto, PID:     2897
06-17 14:21:45.760 E/AndroidRuntime( 2897): java.lang.RuntimeException:     java.lang.reflect.InvocationTargetException
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at     com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
06-17 14:21:45.760 E/AndroidRuntime( 2897): Caused by: java.lang.reflect.InvocationTargetException
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at java.lang.reflect.Method.invoke(Native Method)
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at java.lang.reflect.Method.invoke(Method.java:372)
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
06-17 14:21:45.760 E/AndroidRuntime( 2897):     ... 1 more
06-17 14:21:45.760 E/AndroidRuntime( 2897): Caused by: md52ce486a14f4bcd95899665e9d932190b.JavaProxyThrowable:     System.NullReferenceException: Object reference not set to an instance of an object
06-17 14:21:45.760 E/AndroidRuntime( 2897): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () <IL 0x00011, 0x0004b>
06-17 14:21:45.760 E/AndroidRuntime( 2897): at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>m__0 (object) <IL 0x00006, 0x0003b>
06-17 14:21:45.760 E/AndroidRuntime( 2897): at Android.App.SyncContext/<Post>c__AnonStorey0.<>m__0 () [0x00000] in /Users/builder/data/lanes/monodroid-mavericks-monodroid-5.1-series/d419c934/source/monodroid/src/Mono.Android/src/Android.App/SyncContext.cs:18
06-17 14:21:45.760 E/AndroidRuntime( 2897): at Java.Lang.Thread/RunnableImplementor.Run () [0x0000b] in /Users/builder/data/lanes/monodroid-mavericks-monodroid-5.1-series/d419c934/source/monodroid/src/Mono.Android/src/Java.Lang/Thread.cs:36
06-17 14:21:45.760 E/AndroidRuntime( 2897): at Java.Lang.IRunnableInvoker.n_Run (intptr,intptr) [0x00009] in /Users/builder/data/lanes/monodroid-mavericks-monodroid-5.1-series/d419c934/source/monodroid/src/Mono.Android/platforms/android-21/src/generated/Java.Lang.IRunnable.cs:71
06-17 14:21:45.760 E/AndroidRuntime( 2897): at (wrapper dynamic-method) object.5b2f2ea1-978e-4306-9701-97a7ac2d86c0 (intptr,intptr) <IL 0x00011, 0x0001f>
06-17 14:21:45.760 E/AndroidRuntime( 2897): 
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at mono.java.lang.RunnableImplementor.n_run(Native Method)
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:29)
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at android.os.Handler.handleCallback(Handler.java:739)
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at android.os.Handler.dispatchMessage(Handler.java:95)
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at android.os.Looper.loop(Looper.java:135)
06-17 14:21:45.760 E/AndroidRuntime( 2897):     at android.app.ActivityThread.main(ActivityThread.java:5257)
06-17 14:21:45.760 E/AndroidRuntime( 2897):     ... 4 more
06-17 14:21:49.772 I/Process ( 2897): Sending signal. PID: 2897 SIG: 9    

0 个答案:

没有答案