Xamarin IOS 无法创建控制器异步任务
Xamarin IOS can't create controller async task
我会尽力用英语来解释这个问题。
我目前正在尝试使用 Xamarin 来检查我们是否会在此基础上迁移我们的 IOS 应用程序和 Android 应用程序,因为它看起来真的很不错。
我做的小测试只是测试我的简单登录页面。
我是 CSharp 的新手,如果我提出愚蠢和简单的问题,请提前道歉...
先介绍实现,再介绍问题post。
[实施]
这就是我使用 nuggets 的 RestSharp (Rest library client) 库所做的。我有一个共享项目,将在 Android 应用程序和 IOs 应用程序中使用(以便仅完成一次工作)。我正在 Mac.
上使用 Xamarin Studio
在我的 LoginApiManager.cs 中,我有一个这样的 "basic" 实现:
public interface UserConnectionStates
{
//Regroup all state created above
void userIsConnected(User user);
void userConnectionFailed(IRestResponse<User> response);
void userDisconnected();
}
public class LoginApiManager : RestManager
{
//Used for instance and shared element
public static LoginApiManager instance;
//Permits to store the information about the current loged in user
private User loggedInUser;
//All listeners for that class
private List<UserConnectionStates> userConnectionStatesListeners = new List<UserConnectionStates>();
public LoginApiManager()
{
//Create the the Rest Client to make Api Calls
base.client = new RestClient();
client.BaseUrl = new Uri(apiPath);
client.Authenticator = new HttpBasicAuthenticator(null, null);
}
public static LoginApiManager getInstance()
{
if (instance != null)
{
return instance;
}
else
{
return new LoginApiManager();
}
}
//------- UserConnectionStates Listeners accessors --------
public void addUserConnectionStatesListener(UserConnectionStates listener)
{
if (!userConnectionStatesListeners.Contains(listener))
{
userConnectionStatesListeners.Add(listener);
}
}
public void removeUserConnectionStatesListener(UserConnectionStates listener)
{
if (userConnectionStatesListeners.Contains(listener))
{
userConnectionStatesListeners.Remove(listener);
}
}
/*
* Permits to connect a user with a given username and password. It will
* call the API and return a User Object containing all information needed
* for connection, including token.
*/
public void connectUserWithUserNameAndPassword(string username, string password)
{
var request = new RestRequest(Method.POST);
request.Resource = "/myApiEndpoints/";
//Add it to the request
request.AddParameter("username", username);
request.AddParameter("password", password);
//Execute the query
client.ExecuteAsync<User>(request, (response) =>
{
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
//We serialize the user from response
loggedInUser = response.Data;
foreach (var l in this.userConnectionStatesListeners)
{
l.userIsConnected(response.Data);
}
}
else
{
//We send error to the code
foreach(var l in this.userConnectionStatesListeners)
{
l.userConnectionFailed(response);
}
}
});
}
}
...好的,让我们继续,我的 LoginViewController 实现接口 UserConnectionStates 并将自己引用到侦听器列表,以便了解不同的连接状态修改。就像这样:
在我的 LoginController.cs
public partial class LoginController : UIViewController, UserConnectionStates
{
//Some code here ...
public override void ViewDidLoad()
{
base.ViewDidLoad();
loginManager = LoginApiManager.getInstance();
loginManager.addUserConnectionStatesListener(this); //we create a listener for information about user connection
}
//Here comme the interface methods...
//Interface for listening user connection state
public void userIsConnected(User user)
{
var alertController = UIAlertController.Create("Connexion", "Connexion Success!",UIAlertControllerStyle.Alert);
alertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null));
this.PresentViewController(alertController, true, null);
}
public void userConnectionFailed(IRestResponse<User> response)
{
var alert= UIAlertController.Create("Connexion", "Unable to connect", UIAlertControllerStyle.Alert);
alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null));
PresentViewController(alert, animated: true, completionHandler: null);
}
public void userDisconnected()
{
}
}
[问题]
...这是我的问题,当 client.ExecuteAsync(request, (response)) 被调用时,作为成功的例子,它会调用由我的 LoginController 的侦听器对象 public void userIsConnected(User user) 实现的接口方法,但是因为它是在另一个线程中调用的,所以它在
处停止
var alertController = UIAlertController.Create("Connexion", "Connexion Success!",UIAlertControllerStyle.Alert);
nos 崩溃只是停止而不做任何事情。
我用一个简单的
做了个测试
IRestResponse response = client.Execute(request);
它之所以有效,是因为该方法是同步的并在同一个线程中调用,但它会锁定 UI 直到任务完成...
在 CSharp 或 Xamarin 中实现这种模式的最佳方式是什么?如果有另一种方法可以做这样的事情,我会学习它,但是因为我是新手,所以我不知道这种事情的最佳实践是什么,而且我没有在文档中找到这个(它是肯定在里面,但不要觉得抱歉)。
老实说,我会重新考虑您当前的代码结构。首先,我会停止使用 RestSharp 并选择:Refit
这是一个非常酷的 post,它可以阐明如何正确构建代码:Mobile resiliency with Xamarin
在您的 iOS 和 Android 应用程序中使用 MVVM。这样您就可以共享 ViewModel 并拥有更多可重用和分离的代码。
我会尽力用英语来解释这个问题。 我目前正在尝试使用 Xamarin 来检查我们是否会在此基础上迁移我们的 IOS 应用程序和 Android 应用程序,因为它看起来真的很不错。
我做的小测试只是测试我的简单登录页面。
我是 CSharp 的新手,如果我提出愚蠢和简单的问题,请提前道歉...
先介绍实现,再介绍问题post。
[实施]
这就是我使用 nuggets 的 RestSharp (Rest library client) 库所做的。我有一个共享项目,将在 Android 应用程序和 IOs 应用程序中使用(以便仅完成一次工作)。我正在 Mac.
上使用 Xamarin Studio在我的 LoginApiManager.cs 中,我有一个这样的 "basic" 实现:
public interface UserConnectionStates
{
//Regroup all state created above
void userIsConnected(User user);
void userConnectionFailed(IRestResponse<User> response);
void userDisconnected();
}
public class LoginApiManager : RestManager
{
//Used for instance and shared element
public static LoginApiManager instance;
//Permits to store the information about the current loged in user
private User loggedInUser;
//All listeners for that class
private List<UserConnectionStates> userConnectionStatesListeners = new List<UserConnectionStates>();
public LoginApiManager()
{
//Create the the Rest Client to make Api Calls
base.client = new RestClient();
client.BaseUrl = new Uri(apiPath);
client.Authenticator = new HttpBasicAuthenticator(null, null);
}
public static LoginApiManager getInstance()
{
if (instance != null)
{
return instance;
}
else
{
return new LoginApiManager();
}
}
//------- UserConnectionStates Listeners accessors --------
public void addUserConnectionStatesListener(UserConnectionStates listener)
{
if (!userConnectionStatesListeners.Contains(listener))
{
userConnectionStatesListeners.Add(listener);
}
}
public void removeUserConnectionStatesListener(UserConnectionStates listener)
{
if (userConnectionStatesListeners.Contains(listener))
{
userConnectionStatesListeners.Remove(listener);
}
}
/*
* Permits to connect a user with a given username and password. It will
* call the API and return a User Object containing all information needed
* for connection, including token.
*/
public void connectUserWithUserNameAndPassword(string username, string password)
{
var request = new RestRequest(Method.POST);
request.Resource = "/myApiEndpoints/";
//Add it to the request
request.AddParameter("username", username);
request.AddParameter("password", password);
//Execute the query
client.ExecuteAsync<User>(request, (response) =>
{
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
//We serialize the user from response
loggedInUser = response.Data;
foreach (var l in this.userConnectionStatesListeners)
{
l.userIsConnected(response.Data);
}
}
else
{
//We send error to the code
foreach(var l in this.userConnectionStatesListeners)
{
l.userConnectionFailed(response);
}
}
});
}
}
...好的,让我们继续,我的 LoginViewController 实现接口 UserConnectionStates 并将自己引用到侦听器列表,以便了解不同的连接状态修改。就像这样:
在我的 LoginController.cs
public partial class LoginController : UIViewController, UserConnectionStates
{
//Some code here ...
public override void ViewDidLoad()
{
base.ViewDidLoad();
loginManager = LoginApiManager.getInstance();
loginManager.addUserConnectionStatesListener(this); //we create a listener for information about user connection
}
//Here comme the interface methods...
//Interface for listening user connection state
public void userIsConnected(User user)
{
var alertController = UIAlertController.Create("Connexion", "Connexion Success!",UIAlertControllerStyle.Alert);
alertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null));
this.PresentViewController(alertController, true, null);
}
public void userConnectionFailed(IRestResponse<User> response)
{
var alert= UIAlertController.Create("Connexion", "Unable to connect", UIAlertControllerStyle.Alert);
alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null));
PresentViewController(alert, animated: true, completionHandler: null);
}
public void userDisconnected()
{
}
}
[问题]
...这是我的问题,当 client.ExecuteAsync(request, (response)) 被调用时,作为成功的例子,它会调用由我的 LoginController 的侦听器对象 public void userIsConnected(User user) 实现的接口方法,但是因为它是在另一个线程中调用的,所以它在
处停止 var alertController = UIAlertController.Create("Connexion", "Connexion Success!",UIAlertControllerStyle.Alert);
nos 崩溃只是停止而不做任何事情。
我用一个简单的
做了个测试IRestResponse response = client.Execute(request);
它之所以有效,是因为该方法是同步的并在同一个线程中调用,但它会锁定 UI 直到任务完成...
在 CSharp 或 Xamarin 中实现这种模式的最佳方式是什么?如果有另一种方法可以做这样的事情,我会学习它,但是因为我是新手,所以我不知道这种事情的最佳实践是什么,而且我没有在文档中找到这个(它是肯定在里面,但不要觉得抱歉)。
老实说,我会重新考虑您当前的代码结构。首先,我会停止使用 RestSharp 并选择:Refit
这是一个非常酷的 post,它可以阐明如何正确构建代码:Mobile resiliency with Xamarin
在您的 iOS 和 Android 应用程序中使用 MVVM。这样您就可以共享 ViewModel 并拥有更多可重用和分离的代码。