Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asynchronous 如何将async/await与期望基于回调的异步活动的SDK一起使用_Asynchronous_Xamarin_Xamarin.android_Async Await_Task Parallel Library - Fatal编程技术网

Asynchronous 如何将async/await与期望基于回调的异步活动的SDK一起使用

Asynchronous 如何将async/await与期望基于回调的异步活动的SDK一起使用,asynchronous,xamarin,xamarin.android,async-await,task-parallel-library,Asynchronous,Xamarin,Xamarin.android,Async Await,Task Parallel Library,我正在Xamarin表单中实现本机Android Facebook身份验证,并且正在努力解决Facebook SDK打破我的等待/异步链的问题。SDK需要传递IFacebookCallback和GraphRequest.IGraphJSONObjectCallback的实现,它们定义回调以处理结果。我想在请求登录的代码中执行以下操作: public async Task LogInFacebookAsync() { var loginResult = await _facebookMan

我正在Xamarin表单中实现本机Android Facebook身份验证,并且正在努力解决Facebook SDK打破我的等待/异步链的问题。SDK需要传递
IFacebookCallback
GraphRequest.IGraphJSONObjectCallback
的实现,它们定义回调以处理结果。我想在请求登录的代码中执行以下操作:

public async Task LogInFacebookAsync()
{
    var loginResult = await _facebookManager.Login();  
    // do stuff with result
}
然而,以下是我目前正在做的事情。
请求登录的代码:

public void LogInFacebookAsync()
{
    _facebookManager.Login(onFacebookLoginComplete);
}
private async Task<string> onFacebookLoginComplete(FacebookUser fbUser, string errorMessage) 
{
    // do stuff with result
}
是否有任何方法可以包装这些操作,使我“一路异步”

更新: 谢谢你,保罗。我已经按照这些思路思考了,而你真的将解决方案具体化了。我唯一关心的是这个答案是否是线程安全的。如果双击一个按钮或同时进行两个API调用需要登录Facebook,该怎么办?下面是我试图使
LoginAsync()
方法更安全的尝试。然而,我不是线程安全方面的专家,我欢迎所有的批评

private TaskCompletionSource<FacebookUser> _loginTcs;
public async Task<FacebookUser> LoginAsync()
{
    Task<FacebookUser> loginTask = _loginTcs?.Task;
    // Don't want to create a new login request to the Facebook API if one is already being made.
    if (loginTask != null && (loginTask.Status == TaskStatus.Running || loginTask.Status == TaskStatus.WaitingForActivation 
        || loginTask.Status == TaskStatus.WaitingToRun || loginTask.Status == TaskStatus.WaitingForChildrenToComplete))
    {
        return await loginTask.ConfigureAwait(false);
    }

    this._loginTcs = new TaskCompletionSource<FacebookUser>();
    LoginManager.Instance.SetLoginBehavior(LoginBehavior.NativeWithFallback);
    LoginManager.Instance.LogInWithReadPermissions(_context, new List<string> { "public_profile", "email" });
    var user = await this._loginTcs.Task.ConfigureAwait(false);
    return user;
}
private TaskCompletionSource\u loginTcs;
公共异步任务LoginAsync()
{
任务登录任务=_loginTcs?.Task;
//如果Facebook API已经发出登录请求,则不希望创建新的登录请求。
如果(loginTask!=null&&(loginTask.Status==TaskStatus.Running | | loginTask.Status==TaskStatus.WaitingForActivation
||loginTask.Status==TaskStatus.WaitingToRun | | loginTask.Status==TaskStatus.WaitingForChildrenToComplete)
{
返回wait loginTask.configurewait(false);
}
这是._loginTcs=new TaskCompletionSource();
LoginManager.Instance.SetLoginBehavior(LoginBehavior.NativeWithFallback);
LoginManager.Instance.LogInWithReadPermissions(_上下文,新列表{“public_profile”,“email”});
var user=wait this.\u loginTcs.Task.configurewait(false);
返回用户;
}
使用一个。不需要其他任何东西

我对该API了解不多(我很惊讶Xamarin没有提供一个惯用的.NET版本),但大致上,您需要做的是:

向类中添加任务完成源,而不是
\u onLoginComplete
委托:

// public Func<FacebookUser, string, Task> _onLoginComplete;
private TaskCompletionSource<FacebookUser> completion;
更改
OnError
方法以完成有错误的任务:

public void OnError(FacebookException error)
{
    this.completion.TrySetException(error);
}
更改您的
OnCompleted
以设置任务结果:

public void OnCompleted(JSONObject p0, GraphResponse p1)
{       
    // extract user
    this.completion.TrySetResult(fbUser);   
}
更改登录方法以创建任务完成源并返回任务完成源的任务:

public async Task<FacebookUser> LoginAsync()
{
    this.completion = new TaskCompletionSource<FacebookUser>();
    LoginManager.Instance.SetLoginBehavior(LoginBehavior.NativeWithFallback);
    LoginManager.Instance.LogInWithReadPermissions(_context, new List<string> { "public_profile", "email" });
    await this.completion.Task;
}
public异步任务LoginAsync()
{
this.completion=new TaskCompletionSource();
LoginManager.Instance.SetLoginBehavior(LoginBehavior.NativeWithFallback);
LoginManager.Instance.LogInWithReadPermissions(_上下文,新列表{“public_profile”,“email”});
等待这项任务的完成;
}
使用一个。不需要其他任何东西

我对该API了解不多(我很惊讶Xamarin没有提供一个惯用的.NET版本),但大致上,您需要做的是:

向类中添加任务完成源,而不是
\u onLoginComplete
委托:

// public Func<FacebookUser, string, Task> _onLoginComplete;
private TaskCompletionSource<FacebookUser> completion;
更改
OnError
方法以完成有错误的任务:

public void OnError(FacebookException error)
{
    this.completion.TrySetException(error);
}
更改您的
OnCompleted
以设置任务结果:

public void OnCompleted(JSONObject p0, GraphResponse p1)
{       
    // extract user
    this.completion.TrySetResult(fbUser);   
}
更改登录方法以创建任务完成源并返回任务完成源的任务:

public async Task<FacebookUser> LoginAsync()
{
    this.completion = new TaskCompletionSource<FacebookUser>();
    LoginManager.Instance.SetLoginBehavior(LoginBehavior.NativeWithFallback);
    LoginManager.Instance.LogInWithReadPermissions(_context, new List<string> { "public_profile", "email" });
    await this.completion.Task;
}
public异步任务LoginAsync()
{
this.completion=new TaskCompletionSource();
LoginManager.Instance.SetLoginBehavior(LoginBehavior.NativeWithFallback);
LoginManager.Instance.LogInWithReadPermissions(_上下文,新列表{“public_profile”,“email”});
等待这项任务的完成;
}

您可以设置
自动resetEvent
并使用等待的
任务执行waitone。运行
以避免阻塞主线程,类似于:您可以设置
自动resetEvent
并使用等待的
任务执行waitone。运行
以避免阻塞主线程,比如:再详细说明一下,谢谢,这是一个很好的答案!你介意看一下我问题的编辑吗?我试图将实现增强为线程安全,但我不是线程安全方面的专家。再详细说明一下,谢谢,这是一个极好的答案!你介意看一下我问题的编辑吗?我试图增强实现的线程安全性,但我不是线程安全方面的专家。