对于android的四大基本组件(Activity、Service、Broadcast Receiver、Content Provider),
前面已经介绍了Activity,最基本的活动单元,任何一个活动的处理,都需要他,前面介绍的对话框、布局、提示消息、基本内容设置等等。Broadcase Receiver,广播,主要是用于异步接受Intent(信使)今天我们来说一下 Service。
一、Service
Service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过
其中涉及的方法有:
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即可)
"1.0"
encoding=
"utf-8"
?>
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
android:layout_width=
"fill_parent"
android:layout_height=
"fill_parent"
>
android:id=
"@+id/startService"
android:layout_width=
"fill_parent"
android:layout_height=
"wrap_content"
android:text=
"启动服务"
/>
android:id=
"@+id/stopService"
android:layout_width=
"fill_parent"
android:layout_height=
"wrap_content"
android:text=
"停止服务"
/>
对应的后台,直接启动即可,在前面的文中提到StartActivity,但是这里是启动服务,所以采用StartService即可,同样,停止服务,也是StopService。
protected
override
void
OnCreate(Bundle bundle)
{
base
.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
Button start = FindViewById
start.Click += Start_Click;
Button stop = FindViewById
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来显示我们刚才添加的数据。
"1.0"
encoding=
"utf-8"
?>
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
android:layout_width=
"fill_parent"
android:layout_height=
"fill_parent"
>
android:id=
"@+id/MyButton"
android:layout_width=
"fill_parent"
android:layout_height=
"wrap_content"
android:text=
"点击开始添加数据"
/>
android:minWidth=
"25px"
android:minHeight=
"25px"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:id=
"@+id/listView1"
/>
然后,后台创建一个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.Click +=
delegate
{
var
list = FindViewById(Resource.Id.listView1);
list.Adapter = CreateLocalDb();
};
}
private
ArrayAdapter<
string
> CreateLocalDb()
{
FindViewById
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手机上测试了,完全可行,哈哈。看虚拟机效果。直接点击按钮。
今天就到这里……