Mono for Android開發調研筆記


  • 安裝完Mono for Android(簡稱:MonoDroid)之后,可以用MonoDevelop或Visual Studio來開發Mono for Android應用程序;目前只能在模擬器上調試和部署,必須購買后才能在真機上調試和部署;目前遇到的最大的問題是:模擬器上調試速度非常慢,通過單步調試每一行代碼都需要幾秒鍾。有人開了個帖子抱怨以及一些回復的相關討論:http://mono-for-android.1047100.n5.nabble.com/Free-version-Emulator-only-Bye-bye-td5091443.html,另外,如果購買了正式版,那支持直接用設備來調試的相關文章介紹:http://docs.xamarin.com/android/tutorials/debug_on_device
  • MonoDroid應用程序,應該說所有的Android應用程序只要在處理5秒后還未完成,則會自動提示用戶“應用程序無響應,是否結束應用”類似這樣的提示信息。所以我們一般在處理一些可能比較耗時的操作時,比如與服務器進行通信請求數據或Post數據。這里操作都需要通過異步的方式來完成;
  • MonoDroid提供的API與原生Java平台下的Android開發基本一致,類的名稱以及方法名稱都保持一致,這樣只要會開發原生的Android應用,那在MonoDroid下也可以開發;
  • 雖然說MonoTouch, MonoDroid可以允許我們用C#來開發在IOS以及Android應用,但是並不是所有的代碼都只要用c#寫一次就可以在這兩個平台上跑了。實際上,能重用的代碼也許只有業務層的代碼。因為UI的實現,兩種平台不同,MonoDroid下依賴於Mono.Android來實現UI,而MonoTouch下則是用另外一套不同的UI實現方式。實際上Mono更多的是考慮了與原生API一致的方式來開發UI,所以設計了兩套不同的類庫來實現UI架構;所以UI層的代碼無法重用;另外,數據訪問層,也不能共用,因為雖然都是訪問sqlite,但是Mono在這兩個平台上分別對應實現的API不同,MonoTouch下使用:MonoTouch.CoreData,而MonoDroid下使用Mono.Data.Sqlite。當然我們還是可以將數據訪問層進行抽象,比如抽象成IRepository,然后業務層調用IRepository的接口即可,IRepository的具體實現需要基於不同平台分別實現;
  • 之前可以在Windows上跑的Castle框架在MonoDroid上不再支持,編譯會遇到錯誤,因為Castle程序集依賴於System.Configuration這個程序集,但是在MonoDroid平台上沒有這個程序集;MomoDroid平台上支持的.Net程序集有限,見下面的介紹。基於這個原因,但是又希望能像以前那樣使用某個IOC框架,所以找了一個跨各種手機平台的輕量級開源Ioc框架(TinyIoC),該框架非常小,只有一個cs文件就能使用,使用后感覺效果還不錯,基本容器功能都支持了。git開源項目地址:https://github.com/grumpydev/TinyIoC
  • log4net在MonoDroid上也不支持,因為:Log4Net uses classes in .Net namespaces such as System.Web, and System.Diagnostics that are not yet implemented in Mono for Android. 不過幸好,Android平台自帶了一個Log記錄器,在MonoDroid下可以使用Android.Util.Log來記錄日志。如果是用Visual Studio來開發,則可以直接在VS的Output窗口看到日志,另外VS還有一個專門的窗口(View -> Other Windows -> Android Device Logging)用來查看Android記錄的日志。另外,也可以通過命令行的方式查看日志,定位到目錄:C:\Program Files (x86)\Android\android-sdk\platform-tools,執行命令:adb logcat,詳細方法可以參考:http://docs.xamarin.com/android/advanced_topics/android_debug_log
  • MonoDroid的數據庫是用sqlite,目前內置支持兩種數據訪問方式:原生方式(游標的方式)以及ADO.NET類似的接口,使用起來ADO.NET的方式非常簡單,我們只需要引用:Mono.Data.SQLite這個程序集就能像ADO.NET那樣來訪問sqlite數據庫了。
游標方式舉例:
//查詢數據
ICursor cursor =  this.db.Query(DatabaseTable,  new[] { KeyRowId, KeyTitle, KeyBody },  nullnullnullnullnull);
//新增數據
var initialValues =  new ContentValues();
initialValues.Put(KeyTitle, title);
initialValues.Put(KeyBody, body);
this.db.Insert(DatabaseTable,  null, initialValues);
//更新數據
var args =  new ContentValues();
args.Put(KeyTitle, title);
args.Put(KeyBody, body);
this.db.Update(DatabaseTable, args, KeyRowId +  " = " + rowId,  null);
//刪除數據
this.db.Delete(DatabaseTable, KeyRowId +  " = " + rowId,  null);
//事務支持
this.db.BeginTransaction();  // Start a transaction.
try {
     var result = func();  // Do update db operations.
    db.SetTransactionSuccessful();     // tell db the update operations successfully.    
     return result;
catch {
     // Error in between database transaction
} finally {
     // commit the transaction. 
    
// if the setTransactionSuccessful method have not been called, then the transaction will auto rollback.    
    db.EndTransaction();  
}

 

ADO.NET方式舉例,(需要引用:Mono.Data.Sqlite)
//查詢數據
public  static IEnumerable<Note> GetAllNotes()
{
     var sql =  " SELECT * FROM ITEMS; ";

     using ( var conn = GetConnection())
    {
        conn.Open();

         using ( var cmd = conn.CreateCommand())
        {
            cmd.CommandText = sql;

             using ( var reader = cmd.ExecuteReader())
            {
                 while (reader.Read())
                     yield  return  new Note(reader.GetInt32( 0), reader.GetString( 1), reader.GetDateTime( 2));
            }
        }
    }
}
//新增和更新數據
public  static  void SaveNote(Note note)
{
     using ( var conn = GetConnection())
    {
        conn.Open();

         using ( var cmd = conn.CreateCommand())
        {

             if (note.Id <  0)
            {
                 //  Do an insert
                cmd.CommandText =  " INSERT INTO ITEMS (Body, Modified) VALUES (@Body, @Modified); SELECT last_insert_rowid(); ";
                cmd.Parameters.AddWithValue( " @Body ", note.Body);
                cmd.Parameters.AddWithValue( " @Modified ", DateTime.Now);

                note.Id = ( long)cmd.ExecuteScalar();
            }
             else
            {
                 //  Do an update
                cmd.CommandText =  " UPDATE ITEMS SET Body = @Body, Modified = @Modified WHERE Id = @Id ";
                cmd.Parameters.AddWithValue( " @Id ", note.Id);
                cmd.Parameters.AddWithValue( " @Body ", note.Body);
                cmd.Parameters.AddWithValue( " @Modified ", DateTime.Now);

                cmd.ExecuteNonQuery();
            }
        }
    }
}
//刪除數據
public  static  void DeleteNote(Note note)
{
     var sql =  string.Format( " DELETE FROM ITEMS WHERE Id = {0}; ", note.Id);

     using ( var conn = GetConnection())
    {
        conn.Open();

         using ( var cmd = conn.CreateCommand())
        {
            cmd.CommandText = sql;
            cmd.ExecuteNonQuery();
        }
    }
}
//事務支持
using ( var conn = GetConnection ()) {
    conn.Open ();
     var transaction = conn.BeginTransaction();
     try
    {
         // Do db operations.
        transaction.Commit();
    }
     catch
    {
        transaction.Rollback();
    }
}
  • ORM,NHibernate不能運行在Mono for Android上,不過手機應用的業務邏輯相對簡單,ORM的需求優先級應該不是很急,暫時可以通過上面的數據訪問方式來訪問sqlite數據庫。
  • 類庫方面,目前支持的.net類庫有限,主要有以下幾個:
 1 mscorlib
 2 System    包含System.Net命名空間,支持HttpWebRequest, HttpWebResponse,這兩個類可以實現與服務器端通信
 3 System.Core   包含IO, LINQ, Collections,etc
 4 System.Data   該類庫實現了ADO.NET的相關基礎架構,如DataReader, DataAdapter, Connection, Command, etc.
 5 System.Data.Services.Client
 6 System.EnterpriseServices
 7 System.Json   提供了簡單的JSON序列化和反序列化支持
 8 System.Numberics
 9 System.Runtime.Serialization
10 System.ServiceModel
11 System.ServiceModel.Web
12 System.Transactions  提供事務支持,包括分布式事務
13 System.Web.Services
14 System.Xml
15 System.Xml.Linq
16 Microsoft.CSharp
17  // 以下幾個是Android開發需要的類庫
18  Mono.Android    MonoDroid核心類庫,該類庫中提供的API與原生的JAVA API基本一致,所以使用起來很方便;
19 Mono.Android.Export
20 Mono.Android.GoogleMaps
21 Mono.Android.Support.v4
22 Mono.CompilerServices.SymbolWriter
23 Mono.CSharp
24 Mono.Data.SQLite  提供封裝了Sqlite數據庫的ADO.NET接口支持
25 Mono.Data.Tds
26 Mono.Security
  • 與服務器通信,可以像平時一樣通過HttpWebRequest或WebClient來發送請求。以下代碼設計了一個通用的通過異步的方式發送HttpWebRequest
///   <summary>
///  異步發送HttpWebRequest
///   </summary>
///   <param name="cookie"></param>
///   <param name="url"></param>
///   <param name="postData"></param>
///   <param name="callback"></param>
public  static  void SendHttpPostRequest(Cookie cookie,  string url,  string postData, Action<HttpWebResponse> callback)
{
     // 解決https下的證書問題
    HttpRequestCredentialHelper.SetDefaultCredentialValidationLogic();
     var request = HttpWebRequest.Create(url)  as HttpWebRequest;
     // 設置請求類型為POST
    request.Method =  " POST ";

     // 設置Post的數據
     if (! string.IsNullOrEmpty(postData))
    {
        request.ContentLength = postData.Length;
        request.ContentType =  " application/x-www-form-urlencoded ";
         using ( var writer =  new StreamWriter(request.GetRequestStream()))
        {
            writer.Write(postData);
            writer.Close();
        }
    }

     // 將Cookie放入請求,以讓服務器知道當前用戶的身份
     var container =  new CookieContainer();
    request.CookieContainer = container;
     if (cookie !=  null)
    {
        container.SetCookies( new Uri(Constants.ROOT_URL),  string.Format( " {0}={1} ", cookie.Name, cookie.Value));
         var logger = DependencyResolver.Resolve<ILoggerFactory>().Create( typeof(HttpWebRequestHelper));
        logger.InfoFormat( " HttpWebRequest CookieName:{0}, Value:{1} ", cookie.Name, cookie.Value);
    }

     // 異步發送請求
    request.BeginGetResponse( new AsyncCallback(asyncResult =>
    {
         var httpRequest = asyncResult.AsyncState  as HttpWebRequest;
         using ( var response = httpRequest.EndGetResponse(asyncResult)  as HttpWebResponse)
        {
            callback(response);
        }
    }), request);
}

  發送請求示例代碼:

HttpWebRequestHelper.SendHttpPostRequest( null , url, postData,

response =>
{
    var response = HttpWebRequestHelper.GetTextFromResponse(response);

    //這里處理HttpWebResponse

    
//如果要反問UI相關元素,則需要封裝為一個委托然后在RunOnUiThread方法內執行
    RunOnUiThread(() =>
    {
        var folders = _taskFolderService.GetAllTaskFolders();
        _listView.Adapter = new TaskFolderAdapter(this, Resource.Layout.TaskFolderListItem, folders.ToArray());
    });
});

  • 分層架構,我覺得我們可以采用以下的分層架構: 
    • UI  界面層,MonoTouch,MonoDroid分別實現
    • Model  模型層,實現核心業務邏輯,代碼可重用,如果采用DDD領域模型來實現,則可以包括:Service,Aggregate,Entity,VO,IRepository
    • Model.Infrastructure  基礎框架層,實現公共基礎代碼,供上層調用,如DI,log,configuration,httprequest, constants, etc
    • Model.Repositories  倉儲實現層,對Model層的IRepository接口的實現,不同平台采用不同實現


更多介紹關於Mono for Android開發的文章:

http://www.cnblogs.com/liping13599168/archive/2012/06/10/2543549.html

 

這一篇是介紹關於開發原生Android應用的文章,基本上文章中提到的方法也同樣適用於Mono for Android

http://blog.csdn.net/wlanye/article/details/7199831

 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM