在HttpClient异常(Xamarin Android)上显示AlertDialog

问题描述:

我的Xamarin Android应用程序使用Web服务,它使用HttpClient连接到它。在没有连接的情况下(例如,当用户没有小区或WiFi连接时),会引发一些问题。我使用async/await从服务器获取数据。下面是从我的代码的摘录:在HttpClient异常(Xamarin Android)上显示AlertDialog

public async Task<String> doLogin(string username, string password) 
    { 
     String url = Constants.loginEndpoint + username + "/" + password + "/"; 
     var uri = new Uri(string.Format(url, string.Empty)); 

     return_string = ""; 

     try 
     { 
      var response = await GetAsync(uri); 
      if (response.IsSuccessStatusCode) 
      { 
       return_string = "success"; 
       // Process the positive response here 
      else 
      { } 
     } 
     catch (Exception ex) 
     { 
      throw new ConnectionException(); 
     } 

     return return_string; 
    } 

我定义了一个custon ConnectionException并要显示一个AlertDialog给用户,告知他们,该请求失败,原因是没有任何联系。用户点击确定后,我想关闭应用程序。我试图以下面的方式显示警告对话框,但它不起作用:

public class ConnectionException : Exception 
{ 
    public ConnectionException() 
    { 
     AlertDialog.Builder alert = new AlertDialog.Builder(myApp.Context); 
     alert.SetTitle("Failure"); 
     alert.SetMessage("Request failed. No connection."); 
     alert.SetPositiveButton("OK", (senderAlert, args) => 
     { 
     }); 

     Dialog dialog = alert.Create(); 
     dialog.Show(); 
    } 

    public ConnectionException(string message) 
     : base(message) 
    { } 

    public ConnectionException(string message, Exception innerException) 
     : base(message, innerException) 
    { } 
} 

这是正确的做法吗?可能不会,因为它不工作。我将不胜感激任何帮助如何实现这一目标。另外,我还没有考虑太多,但这是处理这种异常的首选方法吗?

+1

异常对象本身不应该是负责显示的消息。您也(可能)试图在后台线程上显示UI警报。 – Jason

假设你myApp.ContextActivity,它没有备用堆栈,你可以叫Finish()

var context = myApp.Context; // this needs to be an Activity-based context... 
context.RunOnUiThread(() => 
{ 
    var alertDialog = new AlertDialog.Builder(context) 
     .SetTitle("Failure") 
     .SetMessage("Request failed. No connection.") 
     .SetPositiveButton("OK", (senderAlert, args) => 
     { 
      context.Finish(); 
     }) 
     .Create(); 
    alertDialog.Show(); 
}); 
+0

这是正确的解决方案!谢谢! – jkwi

您是否在多个地方重复使用这个异常,或者这是一次性的? 如果你只使用这个异常一次,没有真正的理由来建立你自己的。 你可能只是捕获异常并从你的catch内发布你的警报。

我知道这不是一个漂亮的写法,但如果它工作,为什么不使用它。

备注: DisplayAlert对您来说可能更容易。这将是一个班轮。

例子:

await DisplayAlert("Failure","Request failed. No connection.", "Ok"); 
+0

DisplayAlert是XF,他只是在做Android – Jason

+0

我知道。我不确定他们是否已经在应用程序中使用XF。如果是,则只需使用DisplayAlert,否则他们可能会忽略该部分。 – Hyren123

你正在处理可能发生的错误的方式包含多个问题,由于几个原因而不是正确的方法。

第一:您的代码不遵循C-Sharp惯例并且包含多种代码异味。我向你展示一个更好,更被接受的风格。

1)C#中的方法通常以大写字母开头。 doLogin变为Login

2)要创建一个新的Uri实例,您不需要格式化您的url-string。 string.Empty不会被使用。所以代码可以简化为await GetAsync(new Uri(...));

3)return_string似乎没有以任何方式在方法外部使用。它是string.Empty或“成功”。为什么不把它切换到布尔?这样您可以轻松检查登录是否成功。返回类型变成bool而不是字符串。

的方法现在看起来是这样的:

public async Task<bool> Login(string username, string password) 
{ 
    //TODO: Do parameter check for username and password 

    try 
    { 
     var response = await GetAsync(new Uri(Constants.loginEndpoint + username + "/" + password + "/")); 

     if (response.IsSuccessStatusCode) 
     { 
      // Process the positive response here 

      return true; 
     } 
     else 
     { 
      return false; 
     } 
    } 
    catch (Exception ex) 
    { 
     throw new ConnectionException(); 
    } 

    return false; 
} 

其次,由@Jason提到,异常不应包含任何UI或业务逻辑。考虑以下内容,这将打破目前的实施。

public async Task<bool> Login(string username, string password) 
{ 
    var connectionEx = new ConnectionException(); 

    try 
    { 
     ... 
    } 
    catch (Exception ex) 
    { 
     throw connectionEx; 
    } 

    ... 
} 

现在你的用户将会看到异常,即使没有任何异常。

最后一件事是,我建议不要捕获异常只是为了抛出自定义异常。原因是,可能还有其他事情也会引发异常。例如,积极响应处理中的某些内容为空。

根据如何登录方法使用,例如直接在Android活动,我会做这样的事情:

public async Task Login(string username, string password) 
{ 
    //TODO: Do parameter check for username and password 

    try 
    { 
     var response = await GetAsync(new Uri(Constants.loginEndpoint + username + "/" + password + "/")); 

     if (response.IsSuccessStatusCode) 
     { 
      // Process the positive response here 
     } 
     else 
     { 
      var alertDialog = new AlertDialog.Builder(context) 
       .SetTitle("Failure") 
       .SetMessage("Request failed.") 
       .SetPositiveButton("OK", (senderAlert, args) => 
        { 
         Finish(); 
        }) 
       .Create(); 

      alertDialog.Show(); 
     } 
    } 
    catch (Exception ex) 
    { 
     var alertDialog = new AlertDialog.Builder(context) 
      .SetTitle("Failure") 
      .SetMessage("Something went wrong (" + ex.Message +")") 
      .SetPositiveButton("OK", (senderAlert, args) => 
       { 
        Finish(); 
       }) 
      .Create(); 

     alertDialog.Show(); 
    } 
} 
+0

感谢您的回答。 1)我通常不用C#编程,这就是为什么我没有遵循上述惯例,所以现在改变aaaall我的代码中的方法仅仅是为了以大写字母开头的方法是毫无意义的。 2)你的建议是对的,我不应该在这里使用string.Empty。 3)字符串作为返回值的目的是能够将指定的消息返回给调用函数。我没有设计和实现服务器API,这就是为什么我想让这个方法足够灵活来处理“消息”的原因。 再次感谢您的回答。 – jkwi

+0

我测试了你的代码,AlertDialog没有显示。相反,在Show()之后引发另一个异常。 – jkwi

+0

好吧,我的不好,这是我抛出异常的代码的另一部分。我使用了@SushiHangover的解决方案,因为AlertDialog是在异步方法的后台线程上创建的,因此您的解决方案无法工作。 – jkwi