2017-08-28 81 views
0

我的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

回答

0

假設你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

0

您是否在多個地方重複使用這個異常,或者這是一次性的? 如果你只使用這個異常一次,沒有真正的理由來建立你自己的。 你可能只是捕獲異常並從你的catch內發佈你的警報。

我知道這不是一個漂亮的寫法,但如果它工作,爲什麼不使用它。

備註: DisplayAlert對您來說可能更容易。這將是一個班輪。

例子:

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

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

+0

我知道。我不確定他們是否已經在應用程序中使用XF。如果是,則只需使用DisplayAlert,否則他們可能會忽略該部分。 – Hyren123

0

你正在處理可能發生的錯誤的方式包含多個問題,由於幾個原因而不是正確的方法。

第一:您的代碼不遵循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