標籤:
原文:Android(Xamarin)之旅(五)
2016年1月23日,北京迎來了很痛苦的一天,凍死寶寶了,一天都沒有出我自己的小黑屋,在這屋子裡自娛自樂。不知道你們呢
對於android的四大基本組件(Activity、Service、Broadcast Receiver、Content Provider),
前面已經介紹了Activity,最基本的活動單元,任何一個活動的處理,都需要他,前面介紹的對話方塊、布局、提示訊息、基本內容設定等等。Broadcase Receiver,廣播,主要是用於非同步接受Intent(信使),在四的時候有一個小例子,今天我們來說一下 Service。
一、Service
Service可以在和多場合的應用中使用,比如播放多媒體的時候使用者啟動了其他Activity這個時候程式要在後台繼續播放,比如檢測SD卡上檔案的變化,再或者在後台記錄你地理資訊位置的改變等等,總之服務嘛,總是藏在後頭的。Service是在一段不定的時間運行在後台,不和使用者互動應用組件。每個Service必須在manifest中 通過<service>來聲明。可以通過contect.startservice和contect.bindserverice來啟動。
其中涉及的方法有:
OnCreate:只會在服務第一次開啟的時候調用,主要負責一些初始化代碼。
OnStartCommand:每次啟動服務都會調用該方法,可能來自StartService或者由系統重啟。一般負責開啟需要長時間的任務。並且該方法還要返回StartCommandResult類型的枚舉,該傳回值將影響系統重啟該服務的細節。
OnDestroy:當服務使用StopSelf或者StopService時調用,主要用來釋放資源等。
需要說明的一點就是在Java裡面寫的時候,我們需要在AndroidManifest.xml裡面添加服務,但是,在Xamarin裡面,不需要這麼複雜,我們直接在開頭加上說明[Service]就可以了。其實就像一個簡單的過濾器一樣。其中過濾器在前面的隱式意圖中已經提到。
[Service] public class MainService : Service { }
建立一個項目,然後再項目中添加一個類,直接加在根目錄下面就可以MainService,然後繼承Service,並且去實現他。
首先要實現的是OnBind方法,這個方法是必須的,所以我們直接return null就可以。
public override IBinder OnBind(Intent intent) { return null; }
然後說說涉及到的方法:OnCreate,這裡的三個方法全都是重寫的,因為,在Android裡面,大部分的方法都是提供的,所以,一般情況下,我們需要做的就是實現各種介面。然後各種繼承就可以。在添加的類裡面添加如下方法。
public override void OnCreate() { base.OnCreate(); Log.Debug("xamarin", "OnCreate_create"); }
OnStartCommand,說一個簡單的技巧,在IDE(VS全球最強大的IDE,沒有之一,哈哈)直接override 方法名,然後直接按一次table鍵。自動補全的哦。
public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId) { Log.Debug("xamarin", "OnStartCommand_start"); return StartCommandResult.Sticky; }
OnDestroy(),同樣,我們直接在debug裡面看就可以。
public override void OnDestroy() { base.OnDestroy(); Log.Debug("xamarin", "OnDestroy_stop"); }
OK,完整的服務代碼我們已經建立完成了。如下
using System;using System.Collections.Generic;using System.Linq;using System.Text;using Android.App;using Android.Content;using Android.OS;using Android.Runtime;using Android.Views;using Android.Widget;using Android.Util;namespace Test022_Service{ [Service] public class MainService : Service { public override void OnCreate() { base.OnCreate(); Log.Debug("xamarin", "OnCreate_create"); } public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId) { Log.Debug("xamarin", "OnStartCommand_start"); return StartCommandResult.Sticky; } public override void OnDestroy() { base.OnDestroy(); Log.Debug("xamarin", "OnDestroy_stop"); } public override IBinder OnBind(Intent intent) { return null; } }}
接下來,我們就來添加介面代碼,在Main.axml裡面添加啟動服務和停止服務的按鈕。(Button即可)
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/startService" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="啟動服務" /> <Button android:id="@+id/stopService" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="停止服務" /></LinearLayout>
對應的後台,直接啟動即可,在前面的文中提到StartActivity,但是這裡是啟動服務,所以採用StartService即可,同樣,停止服務,也是StopService。
protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); SetContentView(Resource.Layout.Main); Button start = FindViewById<Button>(Resource.Id.startService); start.Click += Start_Click; Button stop = FindViewById<Button>(Resource.Id.stopService); stop.Click += Stop_Click; } private void Stop_Click(object sender, EventArgs e) { Toast.MakeText(this, "停止服務", ToastLength.Short).Show(); StartService(new Intent(this, typeof(MainService))); } private void Start_Click(object sender, EventArgs e) { Toast.MakeText(this, "啟動服務", ToastLength.Short).Show(); StopService(new Intent(this, typeof(MainService))); }
到這裡,我們的Service已經完成。啟動項目,在虛擬機器中查看。
,服務啟動成功的時候怎麼查看呢,這裡只有一個提示資訊而已,我們看一下IDE。
點擊我們這裡的輸出視窗。
是不是可以看到了呢,在Service裡面寫的代碼 Log.Debug().
那麼我們怎麼知道到底那個服務啟動了,那麼我們來修改一下其中的代碼即可
OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId)
public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId) { Log.Debug("xamarin", "OnStartCommand_start"); new Thread(() => { Log.Debug("xamarin", startId + "號服務的線程啟動"); Thread.Sleep(1000); Log.Debug("xamarin", startId + "號服務的線程關閉"); StopSelf(startId); }).Start(); return StartCommandResult.Sticky; }
那麼,就有同學問了,這裡的Thread到底是用 Java.Lang還是System.Threading呢,其實在這裡是沒區別的,因為都是啟動一個線程。
OK,運行,查看輸出視窗是不是可以看到呢。
二、Android資料存放區
在Android中,提供了SQLite資料庫,它是輕量級嵌入式資料庫引擎,它支援 SQL 語言,並且只利用很少的記憶體就有很好的效能。現在的主流行動裝置像Android、iPhone等都使用SQLite作為複雜資料的儲存引擎,在我們為行動裝置開發應用程式時,也許就要使用到SQLite來儲存我們大量的資料,所以我們就需要掌握行動裝置上的SQLite開發技巧,SQLiteDatabase類為我們提供了很多種方法,對於添加、更新和刪除來說,我們都可以使用。
我們來做一個測試。首先添加一個新的項目。
首先在頁面上添加一個按鈕,用來建立和添加資料,等等。並且添加一個ListView來顯示我們剛才添加的資料。
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/MyButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="點擊開始添加資料" /> <ListView android:minWidth="25px" android:minHeight="25px" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/listView1" /></LinearLayout>
然後,後台建立一個ArrayAdapter(資料配接器)去接受這些資料,並且顯示在頁面上。
在這裡如果我們要拋出異常的時候,最好用Android內建的SQLiteDatabaseCorruptException,不要用Exception,這個是捕捉不到異常的。
using System;using Android.App;using Android.Content;using Android.Runtime;using Android.Views;using Android.Widget;using Android.OS;using Android.Database.Sqlite;using Android.Database;namespace Test018{ [Activity(Label = "添加資料庫", MainLauncher = true, Icon = "@drawable/myapk")] public class MainActivity : Activity { protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); // Get our button from the layout resource, // and attach an event to it Button button = FindViewById<Button>(Resource.Id.MyButton); button.Click += delegate { var list = FindViewById<ListView>(Resource.Id.listView1); list.Adapter = CreateLocalDb(); }; } private ArrayAdapter<string> CreateLocalDb() { FindViewById<Button>(Resource.Id.MyButton).SetText(Resource.String.InsertDb); ArrayAdapter<string> adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1); string file = ""; try { Random rand = new Random(); // //建立資料庫的時候的路徑 // using (SQLiteDatabase db = this.OpenOrCreateDatabase("1.db", FileCreationMode.Private, null)) { db.ExecSQL("create table IF NOT EXISTS T_Person(ID integer primary key autoincrement,Age integer,Name text)"); for (int i = 0; i < 5; i++) { var item = rand.Next(10, 99); db.ExecSQL("insert into T_Person(Age,Name) values (?,?)", new Java.Lang.Object[] { item, "Jeff" + item }); } using (ICursor cursor = db.RawQuery(" select * from T_Person ", null)) { //ADO.Net.reader.Read() 讀取資料 while (cursor.MoveToNext()) { int id = cursor.GetInt(cursor.GetColumnIndex("ID")); int age = cursor.GetInt(cursor.GetColumnIndex("Age")); string name = cursor.GetString(cursor.GetColumnIndex("Name")); adapter.Add(id + ":我是" + name + ",我今年" + age); } } // //擷取到當前的資料庫路徑 // file = this.GetDatabasePath("1.db").Path; } } // //SQLiteDatabaseCorruptException 拋出資料庫異常 // catch (SQLiteDatabaseCorruptException e) { e.ToString(); adapter.Add("添加失敗!"); } adapter.Add(file); return adapter; } }}
,,可以根據部分注釋去瞭解他們。我們運行一下,看下效果。要找路徑的同學注意最後的哪一句,file = this.GetDatabasePath("1.db").Path;本程式已經在小弟我自己的Android手機上測試了,完全可行,哈哈。看虛擬機器效果。直接點擊按鈕。
是不是感覺自己很帥氣的樣子,其實我就是這麼想的。
看到這篇文章的妹紙,漢字,點一下您那可愛的小手,給推薦一下,小弟這廂有禮了。
Android(Xamarin)之旅(五)