【发布时间】:2018-11-19 15:31:40
【问题描述】:
我正在 Xamarin Forms 中实现原生 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
}
这是我的 FacebookManager 类,它实现了必要的接口。请注意,结果可能来自多个回调方法:OnCancel()、OnError()、OnCompleted(),每个方法都调用上面代码传入的 _onLoginComplete。
public class FacebookManager : Java.Lang.Object, IFacebookManager, IFacebookCallback, GraphRequest.IGraphJSONObjectCallback
{
public Func<FacebookUser, string, Task> _onLoginComplete;
public ICallbackManager _callbackManager;
private Activity _context;
public FacebookManager()
{
this._context = CrossCurrentActivity.Current.Activity;
_callbackManager = CallbackManagerFactory.Create();
LoginManager.Instance.RegisterCallback(_callbackManager, this);
}
public async Task Login(Func<FacebookUser, string, Task> onLoginComplete)
{
_onLoginComplete = onLoginComplete;
LoginManager.Instance.SetLoginBehavior(LoginBehavior.NativeWithFallback);
LoginManager.Instance.LogInWithReadPermissions(_context, new List<string> { "public_profile", "email" });
await Task.CompletedTask;
}
#region IFacebookCallback
public void OnCancel()
{
_onLoginComplete?.Invoke(null, "Canceled!");
}
public void OnError(FacebookException error)
{
_onLoginComplete?.Invoke(null, error.Message);
}
public void OnSuccess(Java.Lang.Object result)
{
var n = result as LoginResult;
if (n != null)
{
var request = GraphRequest.NewMeRequest(n.AccessToken, this);
var bundle = new Android.OS.Bundle();
bundle.PutString("fields", "id, first_name, email, last_name, picture.width(500).height(500)");
request.Parameters = bundle;
request.ExecuteAsync();
}
}
#endregion
#region GraphRequest.IGraphJSONObjectCallback
public void OnCompleted(JSONObject p0, GraphResponse p1)
{
// extract user
_onLoginComplete?.Invoke(fbUser, string.Empty);
}
#endregion
}
有什么方法可以包装这些操作,以便我“一直异步”?
更新:
感谢 Paulo 提供的great answer。我已经按照这些思路进行了思考,而您确实明确了解决方案。我唯一关心的答案是它是线程安全的。如果双击一个按钮或同时进行两个 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;
}
【问题讨论】:
-
您可以设置
AutoResetEvent并使用等待的Task.Run执行waitone 以避免阻塞主线程,例如:stackoverflow.com/a/40616041/4984832
标签: asynchronous xamarin xamarin.android async-await task-parallel-library